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
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;
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();
}
}
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
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
}
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();
}