【问题标题】:EF Core conditional (add) includes to an IQueryableEF Core 条件(添加)包含到 IQueryable
【发布时间】:2018-10-17 09:28:42
【问题描述】:

在 EF6 中我习惯这样做:

var orders = GetAllEntities().Include(x => x.Contact.User);
if (includeProducts)
{
    orders = orders.Include(x => x.ProductOrders.Select(y => y.RentStockOrders));
    orders = orders.Include(x => x.ProductOrders.Select(y => y.Product));
    orders = orders.Include(x => x.ProductOrders.Select(y => y.Currency));
    orders = orders.Include(x => x.ProductOrders.Select(y => y.Coupons));
    orders = orders.Include(x => x.AdditionalCosts);
    orders = orders.Include(x => x.Partner);
    orders = orders.Include(x => x.OrderCoupons.Select(y => y.Coupon.Partner));
    if (includeStock)
    {
        orders = orders.Include(x => x.ProductOrders.Select(y => y.RentStockOrders.Select(z => z.Stock)));
    }
}
if (includeInvoices)
{
    orders = orders.Include(x => x.Invoices.Select(y => y.Attachments));
}

在 EF Core 中无法覆盖 IQueryable,因为它更“类型安全”

第一行返回一个IIncludableQueryable<Order, User>,所以当我执行第二个包含时,它想让它变得不同,例如IIncludableQueryable<Ordr,User,ProductOrder>

我主要有一个GetByIdWithCrudRelations,其中包含一组布尔值,用于选择要包含的内容和不包含的内容。有时它只有两个,但在这种情况下它有 8 个,这意味着如果我需要 if-else 一切,它可能会有很多不同的结果。

有人对此有聪明的解决方案吗?

【问题讨论】:

  • 第二个include是Include还是ThenInclude?看起来您正在执行ThenInclude,它采用之前指定的属性。
  • 这似乎是公司做出一次然后后悔支持它的架构决策之一。处理包含多个实体的事物会很丑陋,并且取决于您包含事物的顺序。
  • @johnny5 我同意这可能不是最好的架构设计,但它也不是最糟糕的设计,获取你想要的数据,不要从数据库中提取超过所需的数据,不要写x不同的方法,不要使用懒加载

标签: c# entity-framework-core iqueryable


【解决方案1】:

您可以使用完全相同的模式。只需从IQueryable<T> 变量开始(注意IIncludableQueryable<T, P> 仍然是IQueryable<T> 并具有额外的ThenInclude 支持)并使用ThenInclude 而不是嵌套的Selects:

IQueryable<Order> orders = GetAllEntities().Include(x => x.Contact.User);
// or var orders = GetAllEntities().Include(x => x.Contact.User).AsQueryable();
if (includeProducts)
{
    orders = orders.Include(x => x.ProductOrders).ThenInclude(y => y.RentStockOrders);
    orders = orders.Include(x => x.ProductOrders).ThenInclude(y => y.Product);
    orders = orders.Include(x => x.ProductOrders).ThenInclude(y => y.Currency);
    orders = orders.Include(x => x.ProductOrders).ThenInclude(y => y.Coupons);
    orders = orders.Include(x => x.AdditionalCosts);
    orders = orders.Include(x => x.Partner);
    orders = orders.Include(x => x.OrderCoupons).ThenInclude(y => y.Coupon.Partner);
    if (includeStock)
    {
        orders = orders.Include(x => x.ProductOrders).ThenInclude(y => y.RentStockOrders).ThenInclude(z => z.Stock);
    }
}
if (includeInvoices)
{
    orders = orders.Include(x => x.Invoices).ThenInclude(y => y.Attachments);
}

请注意,由于 ThenInclude 链不是嵌套的,因此不需要不同的变量名称 xyz 等 - 单个 x 或类似的也可以这样做。

另外,由于Include 是从根目录重新启动包含链,所以可以组合像orders = orders.Include(...) 这样的非条件赋值,例如

orders = orders
    .Include(x => x.ProductOrders).ThenInclude(y => y.RentStockOrders)
    .Include(x => x.ProductOrders).ThenInclude(y => y.Product)
    .Include(x => x.ProductOrders).ThenInclude(y => y.Currency)
    .Include(x => x.ProductOrders).ThenInclude(y => y.Coupons)
    .Include(x => x.AdditionalCosts)
    .Include(x => x.Partner)
    .Include(x => x.OrderCoupons).ThenInclude(y => y.Coupon.Partner);

【讨论】:

  • 哈哈,我总是尽量避免var,而且一次我不会遇到麻烦faceslap
  • 在这种情况下,如何对信息进行排序?例如,我尝试.Include(x =&gt; x.ProductOrders.OrderBy(po =&gt; po.RentStockOrders)).ThenInclude(y =&gt; y.RentStockOrders)但收到 InvalidOperationException
  • @lebarillier 您也无法对 EF6 中的包含项进行排序/过滤。 Include 中唯一允许的 LINQ 运算符是 Select
  • 所以没有解决方案,对 ProductOrders 进行排序?即使在 ef 核心?实际上,我必须返回一个IIncludableQueryable
  • @lebarillier 否定的。 AFAIK 计划在 v5.0 中添加 filtered includes,但未订购。一般来说,集合导航属性是无序的,你应该在 UI 中进行排序,或者在具体化查询后在内存中进行排序。
猜你喜欢
  • 2021-07-12
  • 2023-04-07
  • 2020-03-19
  • 2021-11-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多