如何使用EntityFramework保存对象图,禁用延迟加载,禁用代理和实体是不可跟踪的

时间:2013-10-15 21:15:35

标签: c# asp.net-mvc entity-framework

以下是我使用EF的情况。

  1. Repository获取A的实例并返回表示层(即MVC控制器)

  2. 控制器更改A实例上的某些属性,并将其返回以保持不变。

  3. 在坚持之前,我需要弄清楚对象做了哪些更改,并验证是否允许更改。

  4. 要比较更改,我需要数据库中的旧实例。

  5. 但是EF返回同样脏的实例,所以我无法比较它们。

  6. 我尝试过做什么: 班级结构

    public Class A {
     public B B {get;set;}
    }
    
    public class B {
      public ICollection<A> As {get;set;}
      public C c { get; set;}
    }
    public class C {
    }
    

    B和C映射到同一个数据库表。

    1. 虽然这是因为EF正在跟踪旧实例,并且因为实例上已经调用了save,所以它会返回相同的内部。

    2. 所以我关闭了延迟加载,代理生成,并将对象作为不可跟踪的存储库返回。

    3. 现在EF从DB返回新记录,但是如果在A上更改了某个属性,那么在B的A集合中,它只加载我更改的A实例,而不是整个集合。

    4. 如果我想创建一个新的A并保存,我会执行以下操作

      B b = GetSomeOldB(); A =新A(); a.B = b a.Save();

    5. 所以我基本上将新A添加到上下文中并调用SaveChanges。

    6. Ef返回并且“无法将C转换为B”的异常。

    7. 基本上,我想要的只是在我要求的时候从上下文中获取旧的对象图,与污秽的对象进行比较,让污垢持续存在。

      非常感谢任何帮助!

      以下是最终实施的解决方案: 1.关闭跟踪和代理创建 2.从EF获取原始副本。 3.写这个通用方法来水合实体的新实例

      public ICollection<T> GetOriginalCollection<T>(ICollection<T> changedCollection) where T : class {
            ICollection<T> original = new Collection<T>();
            foreach (var item in changedCollection) {
                //Dont return the newly added ones to the original collection
                if (_context.Entry(item).State != EntityState.Added){
                    original.Add(GetOriginal(item));
                }
            }
            return original;
        }
      
      public T GetOriginal<T>(T changedEntity) where T : class {
            Func<DbPropertyValues, Type, object> getOriginal = null;
            getOriginal = (originalValues, type) =>
            {
                object original = Activator.CreateInstance(type, true);
                foreach (var ptyName in originalValues.PropertyNames) {
                    var property = type.GetProperty(ptyName);
                    object value = originalValues[ptyName];
                    //nested complex object
                    if (value is DbPropertyValues) { 
                        property.SetValue(original, getOriginal(value as DbPropertyValues, property.PropertyType));
                    } else{
                        property.SetValue(original, value);
                    }
                }
                return original;
            };
            return (T)getOriginal(_context.Entry(changedEntity).OriginalValues, typeof(T));
        }
      

1 个答案:

答案 0 :(得分:2)

我认为您想要的是在断开连接的环境中工作。您可以附加断开连接的实体,并通过指定其EntityState来提供图中已更改的内容。如果需要,可以创建类似IObjectState的接口,并在模型中实现,以找出图形中的确切更改。