【问题标题】:Filtering a graph of entity framework objects过滤实体框架对象的图
【发布时间】:2010-07-28 12:44:51
【问题描述】:

我正在尝试将 EF 返回的结果过滤为仅相关的结果 - 在下面的示例中为一年中的结果 (formattedYear) 和订单类型 (filtOrder)

我有一组简单的对象

人 1-M 订单 1-M 订单

这些关系已经在 Model.edmx 中定义

在 SQL 中我会做类似...

select * from PEOPLE inner join ORDERS on ORDERS.PEOPLE_RECNO=PEOPLE.RECORD_NUMBER ORDERLINE.ORDER_RECNO=ORDERS.RECORD_NUMBER 上的内部连接 ​​ORDERLINE 其中 ORDERLINE.SERVICE_YEAR=@formattedYear 和 ORDERS.ORDER_KEY=@filtOrder

我尝试了几种方法...

        var y = _entities.PEOPLE.Include("ORDERS").Where("it.ORDERS.ORDER_KEY=" + filtOrder.ToString()).Include("ORDERLINEs").Where("it.ORDERS.ORDERLINEs.SERVICE_YEAR='" + formattedYear + "'");

        var x = (from hp in _entities.PEOPLE 
                 join ho in _entities.ORDERS on hp.RECORD_NUMBER equals ho.PEOPLE_RECNO
                 join ol in _entities.ORDERLINEs on ho.RECORD_NUMBER equals ol.ORDERS_RECNO
                 where (formattedYear == ol.SERVICE_YEAR) && (ho.ORDER_KEY==filtOrder)
                 select hp
                );

y 失败,ORDER_KEY is not a member of transient.collection... 并且 x 返回了正确的人,但他们附上了他们的所有订单 - 不仅仅是我追求的那些。

我想我错过了一些简单的东西?

【问题讨论】:

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


    【解决方案1】:

    假设您有一个有 100 个订单的人。现在您将这些订单过滤到 10 个。最后您选择拥有这些订单的人。你猜怎么了?该人还有100个订单!

    您要的不是实体,因为您不想要整个实体。您似乎想要的是来自实体的数据的子集。所以项目:

    var x = from hp in _entities.PEOPLE
            let ho = hp.ORDERS.Where(o => o.ORDER_KEY == filtOrder
                                          && o.ORDERLINES.Any(ol => ol.SERVICE_YEAR == formattedYear))
            where ho.Any()
            select new 
            {
                Id = hp.ID,
                Name = hp.Name, // etc.
                Orders = from o in ho
                         select new { // whatever 
            };
    

    【讨论】:

    • 看起来不错,但是,如果您需要在另一种方法中使用结果(想象这是在 DAL 中完成的),使用匿名对象可能是一个问题......返回一个 People 对象?我们会丢失应用于订单的过滤器吗?
    • Craig - 是的,我明白,但出于 Julien 提到的原因,我想避免匿名对象。我只是希望我的存储库能够返回具有正确数据的人,并将其交给在其他情况下可能与整个数据集一起使用的强类型视图。
    • 如果需要,您可以返回 POCO 而不是匿名类型(只需将类型名称粘贴在 new{ 之间)。但是,您不能返回实体类型,因为 EF 不允许部分构造的实体。
    • 谢谢。解决方案是 POCO 和您上面的技术。
    【解决方案2】:

    我不确定您的问题是什么,但以下内容可能会有所帮助。

    在实体框架中,如果您想加载对象图并过滤子对象,那么您可以首先查询子对象并枚举它(即调用 ToList()),以便将子对象提取到内存中。

    然后,当您获取父对象(并且不使用 .include)时,实体框架将能够自行构建图形(但请注意,您可能必须先禁用延迟加载,否则加载时间会很长)。 这是一个示例(假设您的上下文是“db”):

    db.ContextOptions.LazyLoadingEnabled = false;
    
    var childQuery = (from o in db.orders.Take(10) select o).ToList();
    
    var q = (from p in db.people select p).ToList();
    


    现在你会发现每个 people 对象都有十个 order 对象


    编辑:我在编写示例代码时很着急,因此我还没有测试它,我可能错了,声称 .Take(10) 将为每个人的对象带来十个订单,相反,我相信 .Take(10) 在禁用延迟加载时只会带回十个整体订单,(对于启用延迟加载的情况,我必须实际测试结果是什么)并且为了带回十个每个人对象的订单,您可能需要进行更广泛的过滤。

    但是思路很简单,首先获取所有子对象,然后实体框架自行构建图。

    【讨论】:

    • 我前段时间走 POCO 路线,但这是禁用延迟加载、ToList 和子查询的一个有趣的副作用:我会记住它以备将来使用。
    • 不管延迟加载是启用还是禁用,它都可以工作,但是我在提到延迟加载时试图说明的一点是,虽然这背后的理论是因为孩子应该在内存中在加载父节点时仍然是延迟加载,这也需要仔细考虑延迟加载时的结果。
    猜你喜欢
    • 2023-03-14
    • 1970-01-01
    • 1970-01-01
    • 2017-11-08
    • 2011-10-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-14
    相关资源
    最近更新 更多