【问题标题】:Entity Framework 4: Eager Loading (Include) with filters using Self Tracking Entities实体框架 4:使用自跟踪实体的过滤器预加载(包含)
【发布时间】:2011-04-05 11:05:14
【问题描述】:

我有一个解决方案,我使用 RTM 模板创建了自我跟踪实体。我已经在 2 个项目之间拆分了实体和上下文,以便我可以在计划通过 WCF 运行客户端/服务器时重用类型定义。

我的一种服务方法需要返回带有“ProductSku”子对象的“Product”对象图,而这些子对象又具有“ProductPrice”子对象。选择标准将基于“Product”对象的“Name”属性和“ProductPriceObject”的“FinancialPeriodID”属性。目前,我没有在搜索中包含该名称,但我在恢复图表时遇到了问题。

如果我只是简单地执行以下查询(注意,此语法取自 LinqPad 而不是实际的应用程序代码)...

from product in Products.Include("Skus.PriceHistory")
select product

...然后我可以检索我需要的项目的完整对象图,当然此时没有过滤器。

如果相反,我将过滤器介绍如下...

from product in Products.Include("Skus.PriceHistory")
join sku in ProductSkus on product.ID equals sku.ProductID
join price in ProductPrices on sku.ID equals price.ProductSkuID
where price.FinancialPeriodID == 244
select product

...我期望得到的是“Product”对象、子“ProductSku”对象(位于“Product”的“Skus”集合中)及其“ProductPrice”对象(它们是在“ProductSku”的“PriceHistory”集合中) - 但我只取回“Product”对象,“Skus”集合是空的。

我也尝试将查询编码为 ...

from product in Products.Include("Skus.PriceHistory")
from sku in product.Skus
from price in sku.PriceHistory
where price.FinancialPeriodID == 244
select product

...但这也没什么区别。

显然,我一定做错了什么。任何人都可以解释一下我在这几个小时里一直在转圈圈的东西是什么!

【问题讨论】:

    标签: .net sql-server linq ado.net entity-framework-4


    【解决方案1】:

    拥有 Include 并不能保证预先加载,它可能会因为以下原因而被忽略。在这个线程中更好地解释。 您可以手动选择要加载的表格,例如

    var result = from product in Products.Include("Skus.PriceHistory")
    from sku in product.Skus
    from price in sku.PriceHistory
    where price.FinancialPeriodID == 244
    select new { p=product, pricehistory = product.Skus.PriceHistory};
    var products = results.select(pph => pph.product);
    

    https://social.msdn.microsoft.com/Forums/en-US/76bf1f22-7674-4e1e-85d3-68d29404e8db/include-is-ignored-in-a-subquery?forum=adodotnetentityframework

    • 包含仅适用于查询结果中的项目: 投影在查询中的最外层操作。
    • 结果的类型必须是实体类型。
    • 查询不能包含更改类型的操作 Include 和最外层操作之间的结果(即 GroupBy() 或更改结果类型的 Select() 操作)
    • Include 采用的参数是一个点分隔的导航路径 必须可从该类型的实例导航的属性 在最外层操作返回

    【讨论】:

      【解决方案2】:

      编辑:

      怎么样:

      from product in Products.Include("Skus.PriceHistory")
      where product.Skus.Any(s => s.PriceHistory.Any(p => p.FinancialPeriodID == 244))
      select product
      

      Include 已经执行了所有必要的任务来填充导航属性,因此不需要额外连接 where 条件。更重要的是,任何手动连接或投影都会改变查询的形状,并且不会使用 Include

      还要注意 where 条件仅过滤产品。它不会过滤由 Include 加载的数据 - 您将获得至少一个 sku 的所有产品,其价格历史记录为财务期 id 244,但这些产品将加载所有 sku 和价格历史记录。 EF 当前不支持对包含进行过滤。如果您还需要过滤关系,则必须执行单独的查询来获取它们。

      【讨论】:

      • 抱歉,“Skus”和“PriceHistory”都是集合,因此无法在单个语句中一路导航。我担心除了使用 join 或 from 来包含连接之外别无选择,如两个示例所示。还是谢谢。
      • 这可能对@MartinRobins 没有帮助,但它在我自己的项目中帮助了我! +1 这种语法对我有用(可能与原始问题完全不同,我不知道......)
      【解决方案3】:

      也许投影可以做到这一点?

      看看Linq filter collection with EF

      【讨论】:

      • 谢谢,但我真的想尽量减少我传递的对象类型的数量。我已经有了一个非常好的“产品”类型,我只是希望快速加载能够正常工作,以便填充子对象。
      【解决方案4】:

      自跟踪实体无法执行延迟加载。 这就是为什么集合在默认实体生成而不是 STE 中不为空的原因。事实上,如果您在查询中使用它们,您的 Include 永远不会加载相关实体。 现在您的 L2E 查询不正确。我认为你想做这样的事情:

      from p in 
         (from product in Products
          select new 
          { 
             Product = product, 
             Skus = 
                from sku in product.Skus
                select new 
                { 
                   Sku = sku, 
                   Prices = 
                      from price in sku.Prices
                      where price.FinancialPeriodID == 244            
                      select price
                }
          }).AsEnumerable()
      select p.Product;
      

      希望有帮助

      马修

      【讨论】:

      • 我没有尝试使用延迟加载;我正在尝试使用急切加载。如果我删除 where 子句,或者仅基于顶级对象,我会正确获取所有对象。只有当我根据子对象的属性使用 where 子句时,“包含”才会被忽略。
      • 嗨马丁,你找到解决办法了吗,我也有同样的问题
      猜你喜欢
      • 2011-08-24
      • 1970-01-01
      • 1970-01-01
      • 2017-01-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多