指尖世界

分享的乐趣

奇妙的动态代理:EF中返回的对象为什么序列化失败

类别: 观点 更新时间: 2016-02-22

[摘要: 本日有如鹏的门生碰到一个题目:把一个工具保管到Session中(过程中Session)后,Web办事重视启,当从Session读与那个工具的时间报错,提醒是一个“T_Users”背面随着一大串数字]

 今天有如鹏的学生遇到一个问题:把一个对象保存到Session中(进程外Session)后,Web服务器重启,当从Session读取这个对象的时候报错,提示是一个“T_Users”后面跟着一大串数字的类型,不是“T_Users”类型。


    凭着感觉,我问“这个对象是普通对象还是什么对象”,回复说“是Entity Framework返回的对象”,瞬间我知道了:是延迟加载造成的。
下面写个程序验证一下。


    数据库里建立两张表:一张T_Persons表,一张T_Dogs表,T_Dogs表中有一个MasterId字段是指向T_Persons的外键,表示“狗的主人是谁”。
    然后创建数据库的Entity。然后编写下面的代码:

abcEntities e = new abcEntities();
T_Persons p = e.T_Dogs.First().T_Persons;
Type t = p.GetType();
Console.WriteLine("对象类型:"+t);

    第二行代码的意思很显然是:获得T_Dogs中第一个对象的主人对象,然后第三行获得的是对象的类型,我们惊奇的发现打印结果是:System.Data.Entity.DynamicProxies.T_Persons_A2C5F62323A22039FDCBEB40BD……


    很奇怪,不应该是T_Persons类的对象吗,怎么是这么一个怪玩意。


    这就涉及到“延迟加载(LazyLoading)”的原理了。对于需要延迟加载的对象,EF会动态生成一个实体类型的子类,这个子类是一个“动态代理(DynamicProxy)”类,这个类会进行延迟加载的处理。所以我们拿到的对象不直接是T_Persons类的对象,而是“动态代理(DynamicProxy)”类的子类,当然由于这个类是T_Persons的子类,所以“T_Persons p = e.T_Dogs.First().T_Persons”这样用父类的变量指向它也是可以的。多态经常偷偷帮我们做很多奇妙的事情。

    由于这个对象是动态产生的类的对象,当程序重启之后,产生的“动态代理(DynamicProxy)”类和之前的“动态代理(DynamicProxy)”类就是两个类了。所以就会反序列化失败了。


    很多ORM框架中延迟加载都是使用动态代理来实现的,比如Java中的Hibernate或者.Net的移植版NHibernate。



感谢关注 V8指尖世界精品文库频道,v8en.com是专门为互联网人打造的学习交流平台,全面满足互联网人工作与学习需求,更多互联网资讯尽在 V8指尖世界!