Using one of DBML schemes depending on parameter - c#

I have an application which should support two versions of databases based on configuration parameter.
The problem is that there is some slight differences between the types in tables of those databases.
For example on old database, the field is of type tinyint and now it's smallint.
When I try to use the new .dbml file I get a cute InvalidCastException when trying to select anything.
I need two different .dbml schemes with same tables and column names but different types.
I'd like to avoid duplicating the code like:
if (newDatabaseVersionFlag)
{
Data.DatabaseDataContext context = new Data.DatabaseDataContext(connectionString);
Data.Something item = context.Somethings.SingleOrDefault(e => e.Id == id);
item.Sth = (short)5;
item.Sth2 = "sample code";
}
else
{
Data2.DatabaseDataContext context2 = new Data2.DatabaseDataContext(connectionString);
Data2.Something item2 = context2.Somethings.SingleOrDefault(e => e.Id == id);
item2.Sth = (byte)5;
item2.Sth2 = "sample code";
}
And there's a lot more of code than that...
What is the best way to make it neat and clean?

You will be best to create a Proxy Data Context.
The issue is if you have different data types, your compiler will fail unless you are using the var
public class UseMeDataContext:System.Data.Linq.DataContext
{
...
}
UseMeDataContext db ;
if (newDatabaseVersionFlag)
{
db = ((System.Data.Linq.DataContext) new Data.DatabaseContext(connectionString));
}
else
{
db = ((System.Data.Linq.DataContext) new Data2.DatabaseDataContext(connectionString));
}
db.Something item2 = UseMeContext.Somethings.SingleOrDefault(e => e.Id == id);
item2.Sth = (TypeOf(item2.sth))5; // May or May not Need typing
item2.Sth2 = "sample code";

Related

How to execute a stored procedure join without creating a new asp.net model?

I am creating stored procedures in SQL Server database and have been having issues returning the data when called.
I have managed to get it to work, but it feels as if it is a hack job and that I am doing it incorrectly. Please see the code below and let me know if there is a better way to go about doing this. Thank you for taking the time to help me.
create procedure FetchSumOfEmpSalariesByCity
as
begin
select
sum(e.SAL) as TotalSalary, d.LOC as Location
from
EMPS e
join
DEPTs d on e.DEPTNO = d.DEPTNO
group by
d.LOC
end
public class SumOfEmpsSalaryByCity
{
[Key]
public int TotalSalary { get; set; }
public string Location { get; set; }
}
[HttpGet]
[Route("salary")]
public IHttpActionResult GetEMPsSal()
{
using (var db = new KemmitContext())
{
var sp = db.SumOfEmpsSalaryByCities.SqlQuery("FetchSumOfEmpSalariesByCity");
return Ok(sp.ToList());
}
}
I want to do this the correct way. Is there a way to do this without a model? Or am I going about this the right way?
I break these tasks down like this; should it be done with EF or in the database and if it's in the database, should it be a View or an Sp?
Whenever I'm simply selecting data, I use EF either direct to the table for very simple queries or I create a database View for any joins, etc. This can be done in EF but it's god-awful, in any case, IMO these tasks belong in the database, right tool, right job. If you're using code-first, getting your Views across is a bit involved, let me know if you're doing that.
var model = db.v_ObservationAutoComplete // This can be direct to a table or a view
.Where(oa => oa.Observation.Contains(term))
.OrderBy(oa => oa.Observation)
.Select(oa => new
{
label = oa.Observation
}).Take(10);
When I have to update something in a single table, I use EF
t_Section eSection = new t_Section
{
SectionId = model.SectionId,
Section = model.Section,
SectionTypeId = model.SectionTypeId,
SectionOrdinal = model.SectionOrdinal,
ModifyDate = DateTime.Now,
ModifyUserName = User.Identity.Name,
LastChangeId = newChangeId
};
db.Entry(eSection).State = EntityState.Modified;
db.SaveChanges();
If I have to do a multi-table update, I have a couple of different methodologies; 1) returning a simple bool value for a status code/scalar value, or I have to return a result set after doing whatever update I made.
This returns a List
List<string> elements = new List<string>();
try
{
SqlParameter[] parms = new[]
{
new SqlParameter("mpid", myProtocolsId),
new SqlParameter("elid", elementId)
};
elements = db.Database.SqlQuery<string>("p_MyProtocolsOverviewElementRemove #myProtocolsId = #mpid, #elementId = #elid", parms).ToList();
return Json(elements);
}
catch (Exception e)
{
return Json(null);
}
And if I just need a simple value back, something like this;
SqlParameter[] parms = new[]
{
new SqlParameter("chid", changeId),
new SqlParameter("prid", change.ObjectId),
new SqlParameter("psid", change.ProtocolSectionId),
new SqlParameter("inid", change.SecondaryObjectId),
new SqlParameter("acun", User.Identity.Name)
};
result = db.Database.SqlQuery<int>("p_MyProtocolsContentUpdateInterventionAdd #changeId = #chid, #protocolId = #prid, #protocolSectionId = #psid, #interventionId = #inid, #acceptUserName = #acun", parms).FirstOrDefault();
Hope this helps!

Update Object without Select EF6 MySQL

Is it possible to update objects with Entity Framework, without grabbing them first?
Example: Here, I have a function that provides a Primary Key to locate the objects, pulls them, then updates them. I would like to eliminate having to pull the objects first, and simply run an UPDATE query. Removing the need for the SELECT query being generated.
public async Task<int> UpdateChecks(long? acctId, string payorname, string checkaccountnumber, string checkroutingnumber, string checkaccounttype)
{
using (var max = new Max(_max.ConnectionString))
{
var payments = await
max.payments.Where(
w =>
w.maindatabaseid == acctId && (w.paymentstatus == "PENDING" || w.paymentstatus == "HOLD")).ToListAsync();
payments.AsParallel().ForAll(payment =>
{
payment.payorname = payorname;
payment.checkaccountnumber = checkaccountnumber;
payment.checkroutingnumber = checkroutingnumber;
payment.checkaccounttype = checkaccounttype;
payment.paymentmethod = "CHECK";
payment.paymentstatus = "HOLD";
});
await max.SaveChangesAsync();
return payments.Count;
}
}
You can use the Attach() command to attach an entity you already know exists and then call SaveChanges() will will call the appropriate update method. Here is some sample code from the MSDN article on the topic:
on the subject:
var existingBlog = new Blog { BlogId = 1, Name = "ADO.NET Blog" };
using (var context = new BloggingContext())
{
context.Entry(existingBlog).State = EntityState.Unchanged;
// Do some more work...
context.SaveChanges();
}
Note that this is general EF logic, not related to any specific database implementation.

Sitefinity: Dynamic Content query optimization with field values

I will attempt to be as specific as possible. So we are using Sitefinity 8.1.5800, I have a couple dynamic content modules named ReleaseNotes and ReleaseNoteItems. ReleaseNotes has some fields but no reference to ReleaseNoteItems.
Release Note Items has fields and a related data field to ReleaseNotes.
So I can query all ReleaseNoteItems as dynamic content pretty quickly less than a second.
I then use these objects provided by sitefinity and map them to a C# object so I can use strong type. This mapping process is taking almost a minute and using over 600 queries for only 322 items (N+1).
In Short: I need to get all sitefinity objects and Map them to a usable c# object quicker than I currently am.
The method for fetching the dynamic content items (takes milliseconds):
private IList<DynamicContent> GetAllLiveReleaseNoteItemsByReleaseNoteParentId(Guid releaseNoteParentId)
{
DynamicModuleManager dynamicModuleManager = DynamicModuleManager.GetManager(String.Empty);
Type releasenoteitemType = TypeResolutionService.ResolveType("Telerik.Sitefinity.DynamicTypes.Model.ReleaseNoteItems.Releasenoteitem");
string releaseNoteParentTypeString = "Telerik.Sitefinity.DynamicTypes.Model.ReleaseNotes.Releasenote";
var provider = dynamicModuleManager.Provider as OpenAccessDynamicModuleProvider;
int? totalCount = 0;
var cultureName = "en";
Thread.CurrentThread.CurrentUICulture = new CultureInfo(cultureName);
Type releasenoteType = TypeResolutionService.ResolveType("Telerik.Sitefinity.DynamicTypes.Model.ReleaseNotes.Releasenote");
// This is how we get the releasenote items through filtering
DynamicContent myCurrentItem = dynamicModuleManager.GetDataItem(releasenoteType, releaseNoteParentId);
var myMasterParent =
dynamicModuleManager.Lifecycle.GetMaster(myCurrentItem) as DynamicContent;
var relatingItems = provider.GetRelatedItems(
releaseNoteParentTypeString,
"OpenAccessProvider",
myMasterParent.Id,
string.Empty,
releasenoteitemType,
ContentLifecycleStatus.Live,
string.Empty,
string.Empty,
null,
null,
ref totalCount,
RelationDirection.Parent).OfType<DynamicContent>();
IList<DynamicContent> allReleaseNoteItems = relatingItems.ToList();
return allReleaseNoteItems;
}
This is the method that takes almost a minute that is mapping sitefinity object to C# object:
public IList<ReleaseNoteItemModel> GetReleaseNoteItemsByReleaseNoteParent(ReleaseNoteModel releaseNoteItemParent)
{
return GetAllLiveReleaseNoteItemsByReleaseNoteParentId(releaseNoteItemParent.Id).Select(rn => new ReleaseNoteItemModel
{
Id = rn.Id,
Added = rn.GetValue("Added") is bool ? (bool)rn.GetValue("Added") : false,
BugId = rn.GetValue<string>("bug_id"),
BugStatus = rn.GetValue<Lstring>("bugStatus"),
Category = rn.GetValue<Lstring>("category"),
Component = rn.GetValue<Lstring>("component"),
#Content = rn.GetValue<Lstring>("content"),
Criticality = rn.GetValue<Lstring>("criticality"),
Customer = rn.GetValue<string>("customer"),
Date = rn.GetValue<DateTime?>("date"),
Grouped = rn.GetValue<string>("grouped"),
Override = rn.GetValue<string>("override"),
Patch_Num = rn.GetValue<string>("patch_num"),
PublishedDate = rn.PublicationDate,
Risk = rn.GetValue<Lstring>("risk"),
Title = rn.GetValue<string>("Title"),
Summary = rn.GetValue<Lstring>("summary"),
Prod_Name = rn.GetValue<Lstring>("prod_name"),
ReleaseNoteParent = releaseNoteItemParent,
McProductId = GetMcProductId(rn.GetRelatedItems("McProducts").Cast<DynamicContent>()),
}).ToList();
}
Is there any way to optimize this all into one query or a better way of doing this? Taking almost a minute to map this objects is too long for what we need to do with them.
If there is no way we will have to cache the items or make a SQL query. I would rather not do caching or SQL query if I do not have to.
Thank you in advance for any and all help you can provide, I am new to posting questions on stackoverflow so if you need any additional data please let me know.
Is there a reason why you are doing a .ToList() for the items? Is it possible for you to avoid that. In my opinion, most of the time(of the 1 minute) is taken to convert all your items into a list. Conversion from Sitefinity object to C# object is not the culprit here.
Look Arno's answer here: https://plus.google.com/u/0/112295105425490148444/posts/QrsVtxj1sCB?cfem=1
You can use the "Content links manager" to query dynamic modules relationships (both by parent -ParentItemId- or by child -ChildItemId-) much faster:
var providerName = String.Empty;
var parentTitle = "Parent";
var relatedTitle = "RelatedItem3";
DynamicModuleManager dynamicModuleManager = DynamicModuleManager.GetManager(providerName);
Type parentType = TypeResolutionService.ResolveType("Telerik.Sitefinity.DynamicTypes.Model.ParentModules.ParentModule");
Type relatedType = TypeResolutionService.ResolveType("Telerik.Sitefinity.DynamicTypes.Model.RelatedModules.RelatedModule");
ContentLinksManager contentLinksManager = ContentLinksManager.GetManager();
// get the live version of all parent items
var parentItems = dynamicModuleManager.GetDataItems(parentType).Where(i => i.GetValue<string>("Title").Contains(parentTitle) && i.Status == ContentLifecycleStatus.Live && i.Visible);
// get the ids of the related items.
// We use the OriginalContentId property since we work with the live vesrions of the dynamic modules
var parentItemIds = parentItems.Select(i => i.OriginalContentId).ToList();
// get the live versions of all the schedules items
var relatedItems = dynamicModuleManager.GetDataItems(relatedType).Where(i => i.Status == ContentLifecycleStatus.Live && i.Visible && i.GetValue<string>("Title").Contains(relatedTitle));
// get the content links
var contentLinks = contentLinksManager.GetContentLinks().Where(cl => cl.ParentItemType == parentType.FullName && cl.ComponentPropertyName == "RelatedField" && parentItemIds.Contains(cl.ParentItemId) && cl.AvailableForLive);
// get the IDs of the desired parent items
var filteredParentItemIds = contentLinks.Join<ContentLink, DynamicContent, Guid, Guid>(relatedItems, (cl) => cl.ChildItemId, (i) => i.OriginalContentId, (cl, i) => cl.ParentItemId).Distinct();
// get the desired parent items by the filtered IDs
var filteredParentItems = parentItems.Where(i => filteredParentItemIds.Contains(i.OriginalContentId)).ToList();
I would imagine that every release note item under a single release note would be related to the same product wouldn't it?
If so, do you need to do the GetMcProductId method for every item?

Attaching objects retrieved from multiple sources

I have three classes, Fish (which contains two properties of type Chips and MushyPeas respectively), MushyPeas (which contains a property of type Chips) and Chips (which has a Name property).
I am running the following piece of hypothetical code:
int chipsId;
using (var db = new FishContext())
{
var creationChips = new Chips() { Name = "A portion of chips" };
db.Chips.Add(creationChips);
db.SaveChanges();
chipsId = creationChips.ChipsId;
}
Chips retrievedChips1;
using (var db = new FishContext())
{
retrievedChips1 = db.Chips.Where(x => x.ChipsId == chipsId).ToList()[0];
}
Chips retrievedChips2;
using (var db = new FishContext())
{
retrievedChips2 = db.Chips.Where(x => x.ChipsId == chipsId).ToList()[0];
}
using (var db = new FishContext())
{
db.Chips.Attach(retrievedChips1);
db.Chips.Attach(retrievedChips2);
var mushyPeas = new MushyPeas() { Chips = retrievedChips2 };
var fish = new Fish() { Chips = retrievedChips1, MushyPeas = mushyPeas };
db.Fish.Add(fish);
db.ChangeTracker.DetectChanges();
db.SaveChanges();
}
This is to simulate a situation in my real app, in which EF objects (which may actually represent the same database record) are loaded from a variety of different DbContexts and then added to an object tree in another DbContext.
If I don't call the two db.Chips.Attach lines, then brand new Chips entities are created when the Fish object is saved to the database, and assigned new IDs.
Calling db.Chips.Attach solves this issue for one of the retrieved obejcts, but the second Attach call fails with the exception "An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key."
What is the best way to achieve what I want to achieve here?
As a grizzled EF vet, I've come to the conclusion that it's best to avoid using Attach in many cases.
The exception "An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key" is usually misleading since the object that you're trying to attach isn't actually attached to the data context. What happens when you attach an object is it recursively attaches any entities that it references. So, if you attach an entity to the data context, and then attach another entity that references any entity that was implicitly attached previously, you will get this error. The solution is pretty simple:
using (var db = new FishContext())
{
var chips1 = db.Chips.Find(retrievedChips1.Id);
var chips2 = db.Chips.Find(retrievedChips2.Id);
var mushyPeas = new MushyPeas() { Chips = chips2 };
var fish = new Fish() { Chips = chips1, MushyPeas = mushyPeas };
db.Fish.Add(fish);
db.ChangeTracker.DetectChanges();
db.SaveChanges();
}
This guarantees that both entities will be attached to the data context without any sort of ObjectStateManager issues.
You could query the Local collection to check if an entity with the same key is already attached and if yes, use the attached entity:
using (var db = new FishContext())
{
var attachedChips1 = db.Chips.Local
.SingleOrDefault(c => c.ChipsId == retrievedChips1.ChipsId);
if (attachedChips1 == null)
{
db.Chips.Attach(retrievedChips1);
attachedChips1 = retrievedChips1;
}
var attachedChips2 = db.Chips.Local
.SingleOrDefault(c => c.ChipsId == retrievedChips2.ChipsId);
if (attachedChips2 == null)
{
db.Chips.Attach(retrievedChips2);
attachedChips2 = retrievedChips2;
}
var mushyPeas = new MushyPeas() { Chips = attachedChips2 };
var fish = new Fish() { Chips = attachedChips1, MushyPeas = mushyPeas };
//...
}
(The first check doesn't make sense in this simple example because a new context is empty with nothing attached to it. But you get the idea...)
However, in the case that you also want to update the related entities (for example by setting the state to Modified after attaching) it would be a problem if retrievedChips1 and retrievedChips2 have (except the key value) different property values. You had to decide somehow which is the "correct one". But that would be business logic. You just have to hand over one of them to EF and only one. In your scenario it wouldn't matter which one you use because you are only creating a relationship and for this EF will only care about the key value.
Side note: Instead of ...ToList()[0] the more natural way would be ...First() (or Single() in this case because you are querying the key).

EF 4 insert entity in relationship with existing entity

using (EntitiesContainer db = new EntitiesContainer())
{
Language language = db.Languages.SingleOrDefault(x => x.Culture == _session.Language);
Language language2 = new Language { Id = action.Language.Id };
Operation operation = new Operation { Id = action.Operation.Id };
//Operation operation = db.Operations.SingleOrDefault(x => x.Id == action.Operation.Id);
if (!language.Id.Equals(language2.Id))
{
db.Languages.Attach(language2);
action.Language = language2;
}
else
{
action.Language = language;
}
db.Operations.Attach(operation);
//db.ObjectStateManager.ChangeObjectState(operation, System.Data.EntityState.Unchanged);
action.Operation = operation;
//operation.Internals.Add(action);
action.CurrentDetail.Language = language;
action.CurrentDetail.Id = Guid.NewGuid();
action.Id = Guid.NewGuid();
db.SaveChanges();
}
Hello I Try all this scenario in commentary, for link my existing operation to the internal action that inherited from action .. but in any of this scenario, he throw me an error like he want to insert a new operation in the DB (dbo.Operations can accept "Action" NULL value) but the Entity already exist.. Can someone please, give me the golden rule .. to insert entity with relation .. existing or not in EF. It's driving me crazy!
Cordialy,
Julien.
If i understand you correctly (your trying to update a relationship), you can use the stub technique:
Language lang = new Language { Id = action.language_id }; // create stub with ID
db.Languages.Attach(lang); // attach stub to graph
action.language = lang; // update relationship
db.SaveChanges();

Categories