如何过滤嵌套集合Entity Framework对象?

时间:2011-08-16 14:02:47

标签: linq entity-framework entity-framework-4.1 filtering

问题在于: 我需要返回带有过滤嵌套集合的对象集合。 例如:有一个带有订单的商店,我需要返回一个商店的集合,其中包含带有订单的嵌套集合,但没有标记为已删除的客户的订单。

这是我尝试做的事情。但仍然没有运气。任何建议表示赞赏:)

public List<StoreEntity> GetStores(Func<Store, bool> storeFilter, Predicate<OrderEntity> orderFileter)
{
    IQueryable<StoreEntity> storeEntities = Context.Stores
        .Include(o => o.Order)
        .Include(cu => cu.Orders.Select(c => c.Customer))
        .Where(storeFilter)
        //.Where(rcu=>rcu.Orders.Select(cu=>cu.Customer.Deleted==false)) //just test this doesn't work
        .AsQueryable();

    List<StoreEntity> storeEntities = storeEntities.ToList();

    //storeEntities.ForEach(s => s.Orders.ToList().RemoveAll(c=>c.Customer.Deleted==true)); // doesn't work

    foreach (StoreEntity storeEntity in storeEntities)
    {
        storeEntity.Orders.ToList().RemoveAll(r=>r.Customer.Deleted==true);
    }

    return storeEntities;
}

问题是未应用过滤器。已将已删除标记设置为true的客户留在集合中。

3 个答案:

答案 0 :(得分:30)

你不能以“整洁”的方式直接做到这一点,但你有几个选择 首先,您可以在获取商店后显式加载子集合。请参阅Applying filters when explicitly loading related entities部分。

如果您不想额外访问数据库,则必须构建自己的查询并将父集合和过滤后的子集合手动投影到另一个对象上。有关示例,请参阅以下问题:
Linq To Entities - how to filter on child entities
LINQ Query - how sort and filter on eager fetch

修改

顺便说一句,您的第一次.Where(rcu=>rcu.Orders.Select(cu=>cu.Customer.Deleted==false))尝试不起作用,因为您将过滤器应用于父集合(存储)而不是嵌套集合(例如,所有未删除的存储客户)。
逻辑上,过滤嵌套集合的代码应该放在Include方法中。目前,Include仅支持Select声明,但我个人认为现在是时候让EF团队实施以下内容:

.Include(cu => cu.Orders.Select(c => c.Customers.Where(cust => !cust.IsDeleted)));

答案 1 :(得分:3)

您目前拥有的代码存在的问题是这一行:

storeEntity.Orders.ToList().RemoveAll(r=>r.Customer.Deleted==true);

storeEntity.Orders.ToList()返回内容为List<OrderEntity> storeEntity.Orders。从这个新列表中删除所有已删除的客户。但是,在此之后的任何地方都不会使用此列表。

但是,即使它会执行您想要的操作,也会从数据库中删除这些客户,因为您的StoreEntity对象仍然连接到数据上下文!

您真的想在评论Where中首次尝试使用过滤器。请参阅Yakimych的答案以获得帮助。

答案 2 :(得分:-5)

老话题,但我遇到了一个相当类似的问题。我搜索了很多,Yakimych提供的MSDN链接最终暗示我要一个解决方案:明确禁用延迟加载,然后执行查询以过滤导航属性。然后,结果将“附加”到主查询,这将提供类似的内容:

Context.Configuration.LazyLoadingEnabled = false;

var filteredOrders = Context.Orders.Where(x => x.Customer.Delete == false);

IQueryable<StoreEntity> storeEntities = Context.Stores
.Include(o => o.Order)
.Include(cu => cu.Orders.Select(c => c.Customer))
.Where(storeFilter)
.AsQueryable();