基于实体框架的多对多通用更新方法

本文关键字:新方法 更新 框架 于实体 实体 | 更新日期: 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();
    }
}