M K*_* II 32 c# entity-framework
我喜欢AddOrUpdate让你指定一个过滤器来检查以避免添加重复项.但我想要没有更新的类似功能.
现在我做这样的事情:
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();
}
Run Code Online (Sandbox Code Playgroud)
我知道我可以这样做:
db.Profile.AddOrUpdate(p => new {p.LastName, p.FirstName, p.Middle}, newProfile);
db.SaveChanges();
Run Code Online (Sandbox Code Playgroud)
但我宁愿在这种情况下跳过修改数据.
第一个例子做了我想要的,但有更多的代码.在第一个例子中是否有更简单/更清洁的方式来做我想要的事情?
更新:
我喜欢Ognyan Dimitrov的建议.我正在努力实现它.我的模型继承自BaseEntity.我可以在那里放一个通用版本吗?
我的模型定义如下:
public class Address :BaseEntity
{
Run Code Online (Sandbox Code Playgroud)
我的BaseEntity:
public class BaseEntity
{
public virtual T AddIfNotExists<T>(T entity, Expression<Func<T, bool>> predicate = null)
{
var exists = predicate != null ? DbSet.Any(predicate) : DbSet.Any();
return !exists ? DbSet.Add(entity) : null;
}
}
Run Code Online (Sandbox Code Playgroud)
我收到Any(...)和Add(...)的错误.Add(...)的错误是'非静态字段,方法或属性'System.Data.Entity.DbSet.Add(object)''需要对象引用
我应该使用这个.添加(对象)?
更新2:
我创建了这段代码:
public static class DbSetExtensions
{
public static T AddIfNotExists<T>(this DbSet<T> dbSet, T entity, Expression<Func<T, bool>> predicate = null) where T : class, new()
{
var exists = predicate != null ? dbSet.Any(predicate) : dbSet.Any();
return !exists ? dbSet.Add(entity) : null;
}
}
Run Code Online (Sandbox Code Playgroud)
现在我试着像这样称呼它,但这不正确.原谅我缺乏理解.
_db.ProfileIdentifier.AddIfNotExists(newIdentifier,
pi => new {pi.ProfileId, pi.ProfileIdentifierTypeId, pi.ProfileIdentifierValue});
Run Code Online (Sandbox Code Playgroud)
更新 - 解决方案:
我可以像这样调用DbSetextensions:
_db.ProfileIdentifier.AddIfNotExists(newIdentifier,
pi => pi.ProfileId == profileId &&
pi.ProfileIdentifierTypeId == (int)type &&
pi.ProfileIdentifierValue == value);
Run Code Online (Sandbox Code Playgroud)
非常感谢与我合作Ognyan!
Ogn*_*rov 36
您是否尝试检查实体是否存在,如果不存在 - 添加它?像这样 :
UPDATE
using System.Linq.Expressions;
public class ContextWithExtensionExample
{
public void DoSomeContextWork(DbContext context)
{
var uni = new Unicorn();
context.Set<Unicorn>().AddIfNotExists(uni , x => x.Name == "James");
}
}
public static class DbSetExtensions
{
public static T AddIfNotExists<T>(this DbSet<T> dbSet, T entity, Expression<Func<T, bool>> predicate = null) where T : class, new()
{
var exists = predicate != null ? dbSet.Any(predicate) : dbSet.Any();
return !exists ? dbSet.Add(entity) : null;
}
}
Run Code Online (Sandbox Code Playgroud)
您可以直接使用此方法,并记住在调用后调用DbContext.SaveChanges().
解决方案是好的,当您只需要添加一个项目时,但如果您必须添加多个项目,则在性能方面会非常昂贵。我认为有一个更好的解决方案:
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));
}
}
Run Code Online (Sandbox Code Playgroud)
所以以后可以这样使用:
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();
}
Run Code Online (Sandbox Code Playgroud)
我用了类似的东西,阅读这两篇帖子来制作我的代码.我希望帮助那些需要与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
{
/// <summary>
/// Adiciona uma entidade se ela não existe ainda
/// Assinatura semelhante ao AddOrUpdate
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="set">Set onde serão adicionadas as entidades</param>
/// <param name="identifierExpression">Campos usados na comparação</param>
/// <param name="entities">Entidades para adicionar</param>
public static void AddIfNotExists<TEntity>(this IDbSet<TEntity> set, Expression<Func<TEntity, object>> identifierExpression, params TEntity[] entities) where TEntity : class
{
var identifyingProperties = GetProperties<TEntity>(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<BinaryExpression, Expression>(null, (agg, v) => (agg == null) ? v : Expression.AndAlso(agg, v));
var predicate = Expression.Lambda<Func<TEntity, bool>>(matchExpression, new[] { parameter });
if (!set.Any(predicate))
{
set.Add(entity);
}
}
}
private static IEnumerable<PropertyInfo> GetProperties<T>(Expression<Func<T, object>> 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<PropertyInfo>();
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<PropertyInfo>();
}
/// <summary>
/// Faz um set.Any(predicate)
/// Se não existe nada no set então adiciona
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="set">Set onde será adicionada a entidade</param>
/// <param name="predicate">Condição (exemplo: dbUser => dbUser.Nome == "Gustavo")</param>
/// <param name="entity">Entidade para adicionar</param>
/// <returns></returns>
public static T AddIfNotExists<T>(this IDbSet<T> set, Expression<Func<T, bool>> predicate, T entity) where T : class, new()
{
return !set.Any(predicate) ? set.Add(entity) : null;
}
}
}
Run Code Online (Sandbox Code Playgroud)
所有其他答案都不正确。
“先写入后先读取”可能会违反数据完整性,而不会放入事务控件中。
在SQL Server中,可以使用merge语句。但是merge语句在EF中不可用。
归档时间: |
|
查看次数: |
45942 次 |
最近记录: |