How do I upsert a record in ADO.NET EF 4.1?

后端 未结 5 1957
走了就别回头了
走了就别回头了 2021-01-01 23:22

I\'m trying to accomplish something really simple and I can\'t find how to do it using Entity Framework 4.1.

I want a controller method that accepts an object and

相关标签:
5条回答
  • 2021-01-01 23:49

    actually there is a way to informa db context that entity you are trying to insert is changed and now the new one

    _context.MyEntity.Attach(entity);
    _context.MyEntity(entity).State = System.Data.EntityState.Modified;
    
    0 讨论(0)
  • 2021-01-01 23:52

    Unfortunately there is no way to do this without querying database or using stored procedure. The minimalistic code should be:

    public void AddOrModify<T>(T entity, string key) where T : class, IEntity // Implements MyKey 
    {
         using (var context = new MyContainer())
         {
             if (context.Set<T>().Any(e => e.MyKey == key))
             {
                  context.Entry(entity).State = EntityState.Modified;
             } 
             else
             {
                  context.Entry(entity).State = EntityState.Added;
             }
    
             context.SaveChanges();
         }
    }
    
    0 讨论(0)
  • 2021-01-01 23:58

    To perform an UPSERT operation, You might want to consider creating an SP that performs a MERGE.

    http://www.databasejournal.com/features/mssql/article.php/3739131/UPSERT-Functionality-in-SQL-Server-2008.htm

    Whatever way you choose the operation must be atomic or you'll have a race condition. Your SP will probably need a HOLDLOCK to void this ...

    http://weblogs.sqlteam.com/dang/archive/2009/01/31/UPSERT-Race-Condition-With-MERGE.aspx

    0 讨论(0)
  • 2021-01-02 00:04

    In most cases you do not need to explicitly set the EntityState.Modified unless you've disabled change tracking.

    The solution we took was to check the value of the entity identifier:

    if (entity.Id == default(int)) {
        // transient entity so insert
    } else {
        // update
    }
    
    0 讨论(0)
  • 2021-01-02 00:05

    I know this question is old and has an accepted answer, but I think there is a better solution: it doesn't require an extra interface to be implemented or key type to be defined.

    public static class DbSetExtensions
    {
        public static EntityEntry<TEnt> AddIfNotExists<TEnt, TKey>(this DbSet<TEnt> dbSet, TEnt entity, Func<TEnt, TKey> predicate) where TEnt : class
        {
            var exists = dbSet.Any(c => predicate(entity).Equals(predicate(c)));
            return exists
                ? null
                : dbSet.Add(entity);
        }
    
        public static void AddRangeIfNotExists<TEnt, TKey>(this DbSet<TEnt> dbSet, IEnumerable<TEnt> entities, Func<TEnt, TKey> predicate) where TEnt : class
        {
            var entitiesExist = from ent in dbSet
                where entities.Any(add => predicate(ent).Equals(predicate(add)))
                select ent;
    
            dbSet.AddRange(entities.Except(entitiesExist));
        }
    }
    

    So later it can be used like this:

    using (var context = new MyDbContext())
    {
        var user1 = new User { Name = "Peter", Age = 32 };
        context.Users.AddIfNotExists(user1, u => u.Name);
    
        var user2 = new User { Name = "Joe", Age = 25 };
        context.Users.AddIfNotExists(user2, u => u.Age);
    
        // Adds user1 if there is no user with name "Peter"
        // Adds user2 if there is no user with age 25
        context.SaveChanges();
    }
    
    0 讨论(0)
提交回复
热议问题