Problem
What is the most efficient approach to use Entity Framework to implement update row if it exists, otherwise insert new row logic? Or are there any patterns to be seen here?
Asked by Jonathan Wood
Solution #1
If you’re working with a connected object (one loaded from the same context instance), you can just type:
if (context.ObjectStateManager.GetObjectStateEntry(myEntity).State == EntityState.Detached)
{
context.MyEntities.AddObject(myEntity);
}
// Attached object tracks modifications automatically
context.SaveChanges();
You can use something like this if you have any knowledge about the object’s key:
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 tell if an object exists based on its Id, do the following 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();
Answered by Ladislav Mrnka
Solution #2
At namespace System, there is an AddOrUpdate function as of Entity Framework 4.3. Data.Entity.Migrations:
public static void AddOrUpdate<TEntity>(
this IDbSet<TEntity> set,
params TEntity[] entities
)
where TEntity : class
which, according to the document:
To respond to @Smashing1978’s comment, I’ll copy and paste key sections from @Colin’s link.
That stated, I’m taking data from an external service and inserting or modifying current values by primary key (while my local data for customers is read-only) – I’ve been using AddOrUpdate in production for about 6 months with no issues.
Answered by Erki M.
Solution #3
When invoking SaveChanges(), the magic happens and is dependent on the current EntityState. It will be added to the database if the entity has an EntityState.Added, and it will be updated in the database if it has an EntityState.Modified. As a result, you may write an InsertOrUpdate() method like this:
public void InsertOrUpdate(Blog blog)
{
using (var context = new BloggingContext())
{
context.Entry(blog).State = blog.BlogId == 0 ?
EntityState.Added :
EntityState.Modified;
context.SaveChanges();
}
}
More about EntityState
Check Ladislav Mrnka’s answer if you can’t figure out if Id = 0 means it’s a new object or not.
Answered by Stacked
Solution #4
You can construct a generic version like this if you know you’ll be utilizing the same context and won’t be detaching any entities.
public void InsertOrUpdate<T>(T entity, DbContext db) where T : class
{
if (db.Entry(entity).State == EntityState.Detached)
db.Set<T>().Add(entity);
// If an immediate save is needed, can be slow though
// if iterating through many entities:
db.SaveChanges();
}
Of course, database can be a class field, and the function can be static and an extension, but these are the fundamentals.
Answered by ciscoheat
Solution #5
Ladislav’s solution was close, but I had to make a few changes to make it work in EF6 (database-first). My data context was extended with my on AddOrUpdate method, and it appears to be working nicely with disconnected objects so far:
using System.Data.Entity;
[....]
public partial class MyDBEntities {
public void AddOrUpdate(MyDBEntities ctx, DbSet set, Object obj, long ID) {
if (ID != 0) {
set.Attach(obj);
ctx.Entry(obj).State = EntityState.Modified;
}
else {
set.Add(obj);
}
}
[....]
Answered by cdonner
Post is based on https://stackoverflow.com/questions/5557829/update-row-if-it-exists-else-insert-logic-with-entity-framework