I like the fact that AddOrUpdate let's you specify a filter to check to avoid adding duplicates. But I would like similar functionality without the update.
我喜欢AddOrUpdate让我们指定一个过滤器来检查以避免添加重复。但是我希望类似的功能不需要更新。
Right now I do something like this:
现在我做了这样的事情:
var checkProfile = from p in db.Profile
where p => p.LastName == newProfile.lastName
&& p => p.FirstName == newProfile.firstName
&& p => p.Middle== newProfile.middle
select p;
if (checkProfile.FirstOrDefault() == null)
{
db.Profile.Add(newProfile);
db.SaveChanges();
}
I know I can do something like this:
我知道我可以这样做:
db.Profile.AddOrUpdate(p => new {p.LastName, p.FirstName, p.Middle}, newProfile);
db.SaveChanges();
But I would rather skip modifying the data in this case.
但在这种情况下,我宁愿跳过修改数据。
The first example does what I want but with more code. Is there a simpler/cleaner way to do what I want in the first example?
第一个示例执行我想要的操作,但是需要更多的代码。在第一个例子中,有没有更简单/更干净的方法来做我想做的事情?
Update:
更新:
I like Ognyan Dimitrov's suggestion. I'm trying to implement it. My models inherit from BaseEntity. Can I put a generic version of that there?
我喜欢迪米特洛夫的建议。我正在尝试实现它。我的模型继承自BaseEntity。我可以在那里放一个通用的版本吗?
My model is defined:
我的模型定义:
public class Address :BaseEntity
{
My BaseEntity:
我的BaseEntity:
public class BaseEntity
{
public virtual T AddIfNotExists(T entity, Expression> predicate = null)
{
var exists = predicate != null ? DbSet.Any(predicate) : DbSet.Any();
return !exists ? DbSet.Add(entity) : null;
}
}
I'm getting errors for Any(...) and Add(...). The error for Add(...) is 'An object reference is required for the non-static field, method, or property 'System.Data.Entity.DbSet.Add(object)' '
我得到的错误为任何(…)和添加(…)。Add(…)的错误是“非静态字段、方法或属性需要一个对象引用”System.Data.Entity.DbSet.Add(object)“
Should I be using this.Add(object) ?
我应该使用this.Add(object)吗?
Update 2:
更新2:
I've created this code:
我创建了这个代码:
public static class DbSetExtensions
{
public static T AddIfNotExists(this DbSet dbSet, T entity, Expression> predicate = null) where T : class, new()
{
var exists = predicate != null ? dbSet.Any(predicate) : dbSet.Any();
return !exists ? dbSet.Add(entity) : null;
}
}
Now I'm trying to call it like this, but it's not correct. Forgive my lack of understanding.
我试着这样称呼它,但它不正确。请原谅我的不理解。
_db.ProfileIdentifier.AddIfNotExists(newIdentifier,
pi => new {pi.ProfileId, pi.ProfileIdentifierTypeId, pi.ProfileIdentifierValue});
Update - Solution:
更新——解决方案:
I can call the DbSetextensions like this:
我可以这样命名dbsetex张力:
_db.ProfileIdentifier.AddIfNotExists(newIdentifier,
pi => pi.ProfileId == profileId &&
pi.ProfileIdentifierTypeId == (int)type &&
pi.ProfileIdentifierValue == value);
Thanks a lot for working with me Ognyan!!!
非常感谢你和我一起工作!!!
25
Have you tried to check if the entity exists and if not - add it? Like this :
是否尝试检查实体是否存在,如果不存在,添加它?是这样的:
UPDATE
更新
using System.Linq.Expressions;
public class ContextWithExtensionExample
{
public void DoSomeContextWork(DbContext context)
{
var uni = new Unicorn();
context.Set().AddIfNotExists(uni , x => x.Name == "James");
}
}
public static class DbSetExtensions
{
public static T AddIfNotExists(this DbSet dbSet, T entity, Expression> predicate = null) where T : class, new()
{
var exists = predicate != null ? dbSet.Any(predicate) : dbSet.Any();
return !exists ? dbSet.Add(entity) : null;
}
}
You can use this method directly and remember to call DbContext.SaveChanges() after the call.
您可以直接使用这个方法,并记住在调用之后调用DbContext.SaveChanges()。
5
Quoted from MSDN EF article.
引用MSDN的文章。
Insert or update pattern
插入或更新模式
A common pattern for some applications is to either Add an entity as new (resulting in a database insert) or Attach an entity as existing and mark it as modified (resulting in a database update) depending on the value of the primary key. For example, when using database generated integer primary keys it is common to treat an entity with a zero key as new and an entity with a non-zero key as existing. This pattern can be achieved by setting the entity state based on a check of the primary key value.
一些应用程序的常见模式是,根据主键的值将实体添加为新的(导致数据库插入),或者将实体附加为现有的,并将其标记为修改的(导致数据库更新)。例如,当使用数据库生成的整数主键时,通常会将具有0键的实体视为新的实体,而将具有非0键的实体视为现有实体。可以通过基于主键值的检查设置实体状态来实现此模式。
Note that when you change the state to Modified all the properties of the entity will be marked as modified and all the property values will be sent to the database when SaveChanges is called.
注意,当您将状态更改为Modified时,实体的所有属性将被标记为Modified,当调用SaveChanges时,所有属性值将被发送到数据库。
context.Entry(blog).State = blog.BlogId == 0 ?
EntityState.Added :
EntityState.Modified;
context.SaveChanges();
5
I used something like, read these two posts to make my code. I hope to help those in need of a similar signature to AddOrUpdate.
我用这两篇文章来写代码。我希望能帮助那些需要AddOrUpdate类似签名的人。
Entity Framework Add if not exist without update
实体框架如果不存在则添加更新
Making AddOrUpdate change only some properties
做AddOrUpdate只更改一些属性
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
namespace System.Data.Entity.Migrations
{
//
// Summary:
// Metodos de extensão para System.Data.Entity.IDbSet
public static class DbSetMigrationsGustavoExtensions
{
///
/// Adiciona uma entidade se ela não existe ainda
/// Assinatura semelhante ao AddOrUpdate
///
///
/// Set onde serão adicionadas as entidades
/// Campos usados na comparação
/// Entidades para adicionar
public static void AddIfNotExists(this IDbSet set, Expression> identifierExpression, params TEntity[] entities) where TEntity : class
{
var identifyingProperties = GetProperties(identifierExpression).ToList();
var parameter = Expression.Parameter(typeof(TEntity));
foreach (var entity in entities)
{
var matches = identifyingProperties.Select(pi => Expression.Equal(Expression.Property(parameter, pi.Name), Expression.Constant(pi.GetValue(entity, null))));
var matchExpression = matches.Aggregate(null, (agg, v) => (agg == null) ? v : Expression.AndAlso(agg, v));
var predicate = Expression.Lambda>(matchExpression, new[] { parameter });
if (!set.Any(predicate))
{
set.Add(entity);
}
}
}
private static IEnumerable GetProperties(Expression> exp) where T : class
{
Debug.Assert(exp != null);
Debug.Assert(exp.Body != null);
Debug.Assert(exp.Parameters.Count == 1);
var type = typeof(T);
var properties = new List();
if (exp.Body.NodeType == ExpressionType.MemberAccess)
{
var memExp = exp.Body as MemberExpression;
if (memExp != null && memExp.Member != null)
properties.Add(type.GetProperty(memExp.Member.Name));
}
else if (exp.Body.NodeType == ExpressionType.Convert)
{
var unaryExp = exp.Body as UnaryExpression;
if (unaryExp != null)
{
var propExp = unaryExp.Operand as MemberExpression;
if (propExp != null && propExp.Member != null)
properties.Add(type.GetProperty(propExp.Member.Name));
}
}
else if (exp.Body.NodeType == ExpressionType.New)
{
var newExp = exp.Body as NewExpression;
if (newExp != null)
properties.AddRange(newExp.Members.Select(x => type.GetProperty(x.Name)));
}
return properties.OfType();
}
///
/// Faz um set.Any(predicate)
/// Se não existe nada no set então adiciona
///
///
/// Set onde será adicionada a entidade
/// Condição (exemplo: dbUser => dbUser.Nome == "Gustavo")
/// Entidade para adicionar
///
public static T AddIfNotExists(this IDbSet set, Expression> predicate, T entity) where T : class, new()
{
return !set.Any(predicate) ? set.Add(entity) : null;
}
}
}
2
The solution is OK, when you have to add just one item, but it's very expensive in terms of performance in case you have to add multiple items. I think there is a better solution:
解决方案是可以的,当您只需要添加一个项目时,但是如果您需要添加多个项目,那么在性能方面非常昂贵。我认为有更好的解决办法:
public static class DbSetExtensions
{
public static EntityEntry AddIfNotExists(this DbSet dbSet, TEnt entity, Func predicate) where TEnt : class
{
var exists = dbSet.Any(c => predicate(entity).Equals(predicate(c)));
return exists
? null
: dbSet.Add(entity);
}
public static void AddRangeIfNotExists(this DbSet dbSet, IEnumerable entities, Func 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();
}
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();
}
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();
}
1
The only thing that comes to mind is to use IEqualityComparer
, but this doesn't really stop the work, merely abstracts it away and creates cleaner code.
唯一想到的是使用IEqualityComparer
1
What worked for me is this:
对我起作用的是:
public static void AddIfNotExists(this DbSet dbSet, Func predicate, params T [] entities) where T : class, new()
{
foreach (var entity in entities)
{
var newValues = predicate.Invoke(entity);
Expression> compare = arg => predicate(arg).Equals(newValues);
var compiled = compare.Compile();
var existing = dbSet.FirstOrDefault(compiled);
if (existing == null)
{
dbSet.Add(entity);
}
}
}