【问题标题】:Many-To-Many Generic Update Method with Entity Framework 6实体框架 6 的多对多通用更新方法
【发布时间】:2015-09-28 19:56:55
【问题描述】:

我在抽象 DatabaseOperations<T,U> 类中有一个用于实体框架的通用 Update 方法:

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&lt;TrussSet, TrussManagementDatabaseContext&gt; 中的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 对象的所有类中。我可以以某种方式将添加的两行注入通用更新方法,以便为更新方法提供集合属性,加载它们,并将相应的更新集合应用于该实体?提前致谢。

【问题讨论】:

    标签: c# entity-framework orm dependency-injection entity-framework-6


    【解决方案1】:

    查看您的代码,想到以下内容:

    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();
        }
    }
    

    【讨论】:

    • 谢谢,你能举个表达式的例子吗?具体来说,我发现我需要在我的更新方法签名中为 ICollection 提供一个参数:public virtual void Update(T updatedObject, int key, List&lt;Expression&lt;Func&lt;CrudType, ICollection&lt;???&gt;&gt;&gt;&gt; navigationCollections = null) 但该签名会根据调用通用方法的人以及是​​否有多个正在更新的集合而有所不同。
    • 我可能已经通过使用object 解决了这个问题。但是有了表达式,我将如何更新typeof(T).GetProperty(prop).GetValue(updatedObject);
    • 我的意思有点不同 - 使用表达式以更安全的方式传递导航属性名称。看这里stackoverflow.com/q/273941/5311735,例如如何从成员访问表达式中获取属性名称。
    • @ScottH 用使用表达式的示例代码更新了我的答案。
    • 这可以处理嵌套集合导航属性吗?我遇到了麻烦。所以它适用于 TrussSet.Seas,但不适用于 TrussInstance,它具有导航属性 TrussSet,然后具有密封件的导航集合。它会抛出一个ArgumentException:“'TrussInstance' 类型的属性 'Seas' 不是导航属性。Reference 和 Collection 方法只能与导航属性一起使用。使用 Property 或 ComplexProperty 方法。”
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-01
    • 2023-04-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多