实体框架中的AddOrUpdate
本文关键字:AddOrUpdate 框架 实体 | 更新日期: 2023-09-27 18:05:05
我正试图实现我自己的AddOrUpdate
,因为实体框架目前不包含此功能。(我需要它)
我知道这里有类似的问题,但要么没有答案,要么是另一个问题。
所以,当我试图实现更新部分时,我卡住了。这是我的代码:
- @this: my DbSet of entries in Database
- 参数:在数据库中检查条目是否已经存在的属性。
- 条目:要添加或更新的所有条目
public static void AddOrUpdate<T>(this DbSet<T> @this, Func<T, object> parameter, params T[] entries) where T: class, IEntity
{
IEnumerable<object> keysExisting = @this.Select(parameter);
foreach (T entry in entries)
{
bool entryExistsAlready = keysExisting.Contains(parameter.Invoke(entry));
if (!entryExistsAlready)
{
@this.Add(entry);
return;
}
entry.Id = @this.First(w => parameter.Invoke(w).Equals(parameter.Invoke(entry))).Id;
@this.Attach(entry);
@this.Update(entry);
}
}
和完成信息,这就是我调用方法的方式(已经有一个ApplicationUser存储在数据库中,电子邮件"test@test.de"):
db.ApplicationUsers.AddOrUpdate(s => s.Email,
new ApplicationUser{Email="test@test.de", Attribute="modified attribute"}
);
我尝试附加条目,但没有附加。我总是得到以下例外(无论是在Attach()
上,或者,当不附加,在Update()
上:
InvalidOperationException:实体类型'ApplicationUser'的实例不能被跟踪,因为该类型的另一个具有相同键的实例已经被跟踪了。当添加新实体时,对于大多数键类型,如果没有设置键,将创建一个唯一的临时键值(即,如果为其类型分配了键属性的默认值)。如果您显式地为新实体设置键值,请确保它们不与现有实体或为其他新实体生成的临时值冲突。在附加现有实体时,确保只有一个具有给定键值的实体实例附加到上下文。
任何想法,我可以如何更新我的条目?
更新:
我已经尝试了反射,只是设置每个属性的所有值,但ApplicationUser例如具有不可写的属性Role
。所以我的方法调用会丢失数据
使用约定,如果构成实体的主键的所有属性都有默认值(0,null等),则该实体是新的,否则它已经存在:
public TEntity AddOrUpdate<TEntity>(DbContext context, TEntity entity)
where TEntity : class
{
context.Entry(entity).State =
context.KeyValuesFor(entity).All(IsDefaultValue)
? EntityState.Added
: EntityState.Modified;
return entity;
}
private static bool IsDefaultValue(object keyValue)
{
return keyValue == null
|| (keyValue.GetType().IsValueType
&& Equals(Activator.CreateInstance(keyValue.GetType()), keyValue));
}
参考:https://blog.oneunicorn.com/2012/05/03/the-key-to-addorupdate/