【问题标题】:Problem using Include() when serializing Entity Framework 4 POCO classes with WCF使用 WCF 序列化 Entity Framework 4 POCO 类时使用 Include() 的问题
【发布时间】:2011-01-29 01:01:10
【问题描述】:

我有一个带有实体框架 4 模型的 WCF 服务,它使用被序列化并发送到客户端应用程序的 POCO 类。我将LazyLoadingEnabledProxyCreationEnabled 设置为false,并且我正在使用Linq to Entites 来查询实体,并通过List<> 将其返回给客户端。当我不使用 Include() 时,一切都很完美:

public List<TBLTable1> GetTBLTable1(string pCode)
{
  using (PcFactoryEntities oPcFactoryDB = new PcFactoryEntities())
  {
    oPcFactoryDB.ContextOptions.ProxyCreationEnabled = false;
    oPcFactoryDB.ContextOptions.LazyLoadingEnabled = false;
    var oRS = oPcFactoryDB.TBLTable1
      .Where(c => c.Code == pCode).ToList();
    XmlObjectSerializer serializer = new DataContractSerializer(typeof(TBLTable1));
    serializer.WriteObject(new XmlTextWriter(Console.Out) { Formatting = Formatting.Indented }, oRS[0]);
    return oRS;
  }
}

在Linq查询之后,我使用序列化器来模拟POCO类发送到客户端时发生的序列化过程,效果很好。但是,当我添加一个 Include() 来加载该类的导航列表之一时,它开始序列化所有Table2 的导航列表,就好像 LazyLoadingEnabled 设置为 true 一样,它可能会永远序列化整个数据库!

public List<TBLTable1> GetTBLTable1(string pCode)
{
  using (PcFactoryEntities oPcFactoryDB = new PcFactoryEntities())
  {
    oPcFactoryDB.ContextOptions.ProxyCreationEnabled = false;
    oPcFactoryDB.ContextOptions.LazyLoadingEnabled = false;
    var oRS = oPcFactoryDB.TBLTable1
      .Include("TBLTable2")
      .Where(c => c.Code == pCode).ToList();
    XmlObjectSerializer serializer = new DataContractSerializer(typeof(TBLTable1));
    serializer.WriteObject(new XmlTextWriter(Console.Out) { Formatting = Formatting.Indented }, oRS[0]);
    return oRS;
  }
}

为什么会这样?不应该将 LazyLoadingEnabled 设置为 false 应用于手动包含的类并将其所有导航列表返回到 null,就像 Table1 的所有其他导航列表一样?有没有办法解决这个问题,所以我可以用 Table1 返回一些导航列表,它们的导航列表设置为null
提示

【问题讨论】:

    标签: entity-framework serialization entity-framework-4 linq-to-entities poco


    【解决方案1】:

    不要尝试直接序列化实体,而是尝试投影到 DTO 并对其进行序列化。我同意您看到的奇怪行为 - 但可能是 EF 内部图在您序列化实体时接管,但如果您序列化 DTO,EF 不应干预。

    例如:

    var dto = oPcFactoryDB.TBLTable1
                          .Where(x => x.Code == pCode)
                          .Select(x => new SpecialisedDTO
                          {
                             PropertyOne = x,
                             PropertyTwo = x.TBLTable2
                          }).ToList();
    

    然后将其序列化。

    自从您进行投影以来,您无需急切加载 - EF 将根据您提供的查询获取它需要的内容。

    在 N 层情况下,通过线路传输 DTO 而不是纯 POCO 实体通常是一种很好的做法。

    【讨论】:

    • 感谢您的输入,这是解决我的问题的有效方法,但我真的很想知道这是否是 EF 错误,如果我做错了什么或者我是只是错过了一些东西。 Tks
    • 我正在研究您提出的解决方案。我将如何声明 SpecialiseDTS 类?我会有一个 TBLTable1 类型的属性 PropertyOne 吗?谢谢你的时间
    • 是的,两个带有 get/sets 的属性 - TBLTable1 类型的 PropertyOne 和 TBLTable2 类型的 PropertyTwo
    【解决方案2】:

    您在 TBLtable1 到 TBLtable2 上有导航属性吗? .Include() 用于包含链接 va FK 关系的实体,并且 .Include() 传递了导航属性的名称。

    因此,如果您有一个带有 NavigationProperty 的 Person 实体到一个名为 PersonAddresses 的 Addresses 实体,那么您将执行以下操作以获取 Person 及其地址。

    var p = dbContext.Person
             .Where(x => x.Id == id)
             .Include("PersonAddresses")
             .SelectFirstOrDefault;
    

    【讨论】:

    • 谢恩。我确实有一个导航属性,并且包含正在工作。问题是当我使用包含时,对象的序列化变得疯狂,尽管延迟加载被禁用。 Tks
    猜你喜欢
    • 2011-12-28
    • 2011-07-19
    • 2011-11-16
    • 1970-01-01
    • 2023-03-27
    • 1970-01-01
    • 2012-02-12
    • 1970-01-01
    • 2013-12-28
    相关资源
    最近更新 更多