Does anyone have suggestions on the most efficient way to implement "update row if it exists else insert" logic using Entity Framework?
If you are working with attached object (object loaded from the same instance of the context) you can simply use:
if (context.ObjectStateManager.GetObjectStateEntry(myEntity).State == EntityState.Detached)
{
context.MyEntities.AddObject(myEntity);
}
// Attached object tracks modifications automatically
context.SaveChanges();
If you can use any knowledge about the object's key you can use something like this:
if (myEntity.Id != 0)
{
context.MyEntities.Attach(myEntity);
context.ObjectStateManager.ChangeObjectState(myEntity, EntityState.Modified);
}
else
{
context.MyEntities.AddObject(myEntity);
}
context.SaveChanges();
If you can't decide existance of the object by its Id you must exectue lookup query:
var id = myEntity.Id;
if (context.MyEntities.Any(e => e.Id == id))
{
context.MyEntities.Attach(myEntity);
context.ObjectStateManager.ChangeObjectState(myEntity, EntityState.Modified);
}
else
{
context.MyEntities.AddObject(myEntity);
}
context.SaveChanges();
Thanks. Looks like what I need. Can I ask you one question that's been bothering me for a while? Normally, I put my context in a short
using
block. Is it okay to leave the context in memory for a while? For example, during the life of a Windows form? I normally try and clean up database objects to ensure minimum load on the database. Is there no problem waiting to destroy my EF context?Check this: stackoverflow.com/questions/3653009/… object context should live as short as possible but in case of winforms or wpf this can mean that context is living as long as presenter. The linked question contains link to msdn article about using nhibernate session in winforms. The same approach can be used for context.
But what if i need to do this with a list of objects... in my database there is a list of rows with the same id and i want to replace if thew exist or insert if they dont.. how i do it? thanks!
This answer LOOKS awesome, but I'm running into this issue on update: An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key.
Looks like I was just having a bit of an issue with fetching the existing object so as to retrieve its key before doing the update; detaching that lookup object first helped fix it.