基于实体框架的多对多通用更新方法
本文关键字:新方法 更新 框架 于实体 实体 | 更新日期: 2023-09-27 18:14:50
我有一个通用的Update
方法实体框架在一个抽象的DatabaseOperations<T,U>
类:
public virtual void Update(T updatedObject, int key)
{
if (updatedObject == null)
{
return;
}
using (var databaseContext = new U())
{
databaseContext.Database.Log = Console.Write;
T foundEntity = databaseContext.Set<T>().Find(key);
databaseContext.Entry(foundEntity).CurrentValues.SetValues(updatedObject);
databaseContext.SaveChanges();
}
}
然而,这并不能处理多对多关系。这个多对多的更新问题可以通过在TrussSetDatabaseOperations : DatabaseOperations<TrussSet, TrussManagementDatabaseContext>
中重写Update
方法来克服,如下所示:
public override void Update(TrussSet updatedTrussSet, int key)
{
if (updatedTrussSet == null)
{
return;
}
using (var databaseContext = new TrussManagementDatabaseContext())
{
databaseContext.Database.Log = Console.Write;
TrussSet foundTrussSet = databaseContext.TrussSets.Find(key);
databaseContext.Entry(foundTrussSet).CurrentValues.SetValues(updatedTrussSet)
// Update the many-to-many relationship of TrussSets to Seals
databaseContext.Entry(foundTrussSet).Collection(trussSet => trussSet.Seals).Load();
databaseContext.Entry(foundTrussSet).Collection(trussSet => trussSet.Seals).CurrentValue = updatedTrussSet.Seals;
databaseContext.SaveChanges();
}
}
然而,这种重写会扩散到所有从DatabaseOperations
继承并拥有TrussSet对象的类。我能否以某种方式将添加的两行注入到通用更新方法中,以便更新方法获得集合属性,加载它们,并将各自更新的集合应用于该实体?
查看您的代码,您会想到以下内容:
public virtual void Update(T updatedObject, int key, params string[] navigationProperties) {
if (updatedObject == null) {
return;
}
using (var databaseContext = new U()) {
databaseContext.Database.Log = Console.Write;
T foundEntity = databaseContext.Set<T>().Find(key);
var entry = databaseContext.Entry(foundEntity);
entry.CurrentValues.SetValues(updatedObject);
foreach (var prop in navigationProperties) {
var collection = entry.Collection(prop);
collection.Load();
collection.CurrentValue = typeof(T).GetProperty(prop).GetValue(updatedObject);
}
databaseContext.SaveChanges();
}
}
如果你想要更多的类型安全,你也可以使用表达式来代替字符串(然后从这些表达式中提取属性名)。
更新:这就是我在这种情况下"使用表达式"的意思:
public virtual void Update(T updatedObject, int key, params Expression<Func<T, IEnumerable>>[] navigationProperties) {
if (updatedObject == null) {
return;
}
using (var databaseContext = new U()) {
databaseContext.Database.Log = Console.Write;
T foundEntity = databaseContext.Set<T>().Find(key);
var entry = databaseContext.Entry(foundEntity);
entry.CurrentValues.SetValues(updatedObject);
foreach (var prop in navigationProperties) {
string memberName;
var member = prop.Body as MemberExpression;
if (member != null)
memberName = member.Member.Name;
else throw new Exception("One of the navigationProperties is not a member access expression");
var collection = entry.Collection(memberName);
collection.Load();
collection.CurrentValue = typeof (T).GetProperty(memberName).GetValue(updatedObject);
}
databaseContext.SaveChanges();
}
}