如何保存的EntityFramework对象图,延迟加载禁用,禁用代理和实体是非可追踪 [英] How to save an object graph with EntityFramework, lazy load disabled, proxy disabled and entities are non trackable

查看:142
本文介绍了如何保存的EntityFramework对象图,延迟加载禁用,禁用代理和实体是非可追踪的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

下面是使用到EF我的情况。


  1. 库获取的实例,并返回到presentation层(即MVC控制器)


  2. 在控制器上的的情况下更改某些属性和给定的回坚持。


  3. 坚持之前,我需要弄清楚什么样的变化做对象,如果变化是允许或不允许验证。


  4. 要比较的变化,我需要的旧实例从数据库中。


  5. 但EF返回相同的脏实例,因此我无法对它们进行比较。


我试着这样做:
班级结构

  public类{
 大众B B {获取;设置;}
}公共类B {
  公众的ICollection< A>由于{获取;设置;}
  大众C C {搞定;组;}
}
公共C类{
}

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


  1. 虽然那是因为EF是跟踪老的实例,因为保存至今尚未呼吁实例,因此它的返回回同一inatce。


  2. 所以我关掉延迟加载,代理根和存储库返回的对象作为不可追踪的。


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


  4. 当如果我想创建一个新的A和保存,我做以下

    B B = GetSomeOldB();
    A中新= A();
    A·B = B
    a.Save();


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


  6. EF收益和异常无法施展C到B。


基本上,我要的是从当我问的情况下得到的是旧的对象图,用脏一个给人脏坚持比较。

真的AP preciate任何帮助!

下面是最终实施的解决方案:
1.重新打开的跟踪和代理的创建
2. EF获取原单副本。
3.写到这泛型方法来滋润实体的新实例

 公开的ICollection< T> GetOriginalCollection< T>(ICollection的< T> changedCollection)其中T:类{
      ICollection的< T>原=新的集合< T>();
      的foreach(在changedCollection VAR项){
          //不要返回新添加的那些原始集合
          如果(_context.Entry(项目).STATE!= EntityState.Added){
              original.Add(GetOriginal(项目));
          }
      }
      返回原来的;
  }公共ŧGetOriginal< T>(T changedEntity)其中T:类{
      FUNC< D​​bPropertyValues​​,类型,对象> getOriginal = NULL;
      getOriginal =(originalValues​​,类型)=>
      {
          原来的对象= Activator.CreateInstance(类型,真正的);
          的foreach(在originalValues​​.PropertyNames VAR ptyName){
              VAR财产= type.GetProperty(ptyName);
              对象值= originalValues​​ [ptyName]
              //嵌套的复杂对象
              如果(价值DbPropertyValues​​){
                  property.SetValue(原件,getOriginal(价值DbPropertyValues​​,property.PropertyType));
              }其他{
                  property.SetValue(原件,价值);
              }
          }
          返回原来的;
      };
      回报(T)getOriginal(_context.Entry(changedEntity).OriginalValues​​的typeof(T));
  }


解决方案

我想你想在断开连接的环境中工作的。您可以将断开的实体,并提供图形通过指定EntityState什么改变。如果你愿意,你可以像IObjectState创建界面,并在您的模型实现找出了一张完全改变了。

Here is the situation I am into using EF.

  1. Repository gets an instance of A and returns to the presentation tier (i.e. MVC controllers)

  2. The controllers change certain properties on A's instance and the given it back to persist.

  3. Before persisting, I need to figure out what change was done to the object and validate if the change is permitted or not.

  4. To compare the change, I need the old instance from the database.

  5. But EF returns the same dirtied instance, so I cannot compare them.

What I tried doing: Class Structure

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 and C map to the same database table.

  1. Though it's because EF is tracking the old instance and since save has yet been called on the instance, so it's returning back the same inatce.

  2. So I turned off lazy loading, proxy gen, and return the objects as non-trackable for the repository.

  3. Now EF returns fresh record from the DB, but If changed some property on A, then in the B's collection of A, it loads only the instance of A that I changed, not the entire collection.

  4. When If I want to create a new A and save, I do the following

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

  5. So I essentially I add the new A to the context and call SaveChanges.

  6. Ef returns and exception that "Unable to cast C to B".

Basically, all I want is to get the old object graph from the context when I ask for, compare with the dirtied one the giving the dirtied to persist.

Would really appreciate any help!!

Here is the solution that finally implemented: 1. Turned back on the Tracking and proxy creation 2. Get the orginal copy from EF. 3. Wrote this generic method to hydrate a new instance of the entity

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

解决方案

I think what you want is working in disconnected environment. You can attach disconnected entities and provide what changed in the graph by specifying its EntityState. If you want you can create Interface like IObjectState and implement in your models to find out what exactly changed in the graph.

这篇关于如何保存的EntityFramework对象图,延迟加载禁用,禁用代理和实体是非可追踪的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆