EF Core linq和条件包含然后包含问题 [英] EF Core linq and conditional include and theninclude problem

查看:176
本文介绍了EF Core linq和条件包含然后包含问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

尝试获取具有多个级别的对象时,我在获取结果时遇到问题。
这是我要大致执行的操作:

I am having a problem with getting a result when trying to get objects with multiple levels. This is what I am trying to do roughly:

_context.Investors.Where(s => s.Id == userId)
    .Include(c => c.Coins) //only want this if some kind of flag is given by the user.
    .ThenInclude(ct => ct.CoinType)
    .Include(c => c.Bricks) //only want this if some kind of flag is given by the user.

基本上,我收到很多标志,指示是否应包括对象的一部分。
我差不多可以用了。像这样:

Essentially I am getting a lot of flags indicating if I should include parts of the object. I got it almost to work. Like this:

_context.Investors.Where(s => s.Id == userId)
    .Select(i => new
    {
        i,
        Bricks = (details & GapiInvestorFlags.Bricks) != GapiInvestorFlags.Bricks ? null : i.Bricks,
        Offers = (details & GapiInvestorFlags.Offers) != GapiInvestorFlags.Offers ? null : i.Offers,
        Coins = (details & GapiInvestorFlags.Coins) != GapiInvestorFlags.Coins ? null : i.Coins,
        CoinTransactions = (details & GapiInvestorFlags.CoinTransactions) != GapiInvestorFlags.CoinTransactions ? null : i.CoinTransactions,
        OfferTransactions = (details & GapiInvestorFlags.OfferTransactions) != GapiInvestorFlags.OfferTransactions ? null : i.OfferTransactions,
        BuyTransactions = (details & GapiInvestorFlags.BuyTransactions) != GapiInvestorFlags.BuyTransactions ? null : i.BuyTransactions,
        SellTransactions = (details & GapiInvestorFlags.SellTransactions) != GapiInvestorFlags.SellTransactions ? null : i.SellTransactions
    }).AsEnumerable()
    .Select(e => e.i).FirstOrDefault();

这可以工作,除了Coins部分也有硬币类型,所以我也需要包括它。但是,当我添加代码时,整个部分将停止工作。

This works except that the Coins section also has a cointype in it so I need to include it too. But when I add my code, the whole section stops working.

这是我尝试过的操作:

_context.Investors.Where(s => s.Id == userId)
    .Include(c => c.Coins)
    .ThenInclude(ct => ct.CoinType)
    .Select(i => new
    {
        i,
        Bricks = (details & GapiInvestorFlags.Bricks) != GapiInvestorFlags.Bricks ? null : i.Bricks,
        Offers = (details & GapiInvestorFlags.Offers) != GapiInvestorFlags.Offers ? null : i.Offers,
        Coins = (details & GapiInvestorFlags.Coins) != GapiInvestorFlags.Coins ? null : i.Coins.Select(c => new { c, c.CoinType }).ToList(),
        CoinTransactions = (details & GapiInvestorFlags.CoinTransactions) != GapiInvestorFlags.CoinTransactions ? null : i.CoinTransactions,
        OfferTransactions = (details & GapiInvestorFlags.OfferTransactions) != GapiInvestorFlags.OfferTransactions ? null : i.OfferTransactions,
        BuyTransactions = (details & GapiInvestorFlags.BuyTransactions) != GapiInvestorFlags.BuyTransactions ? null : i.BuyTransactions,
        SellTransactions = (details & GapiInvestorFlags.SellTransactions) != GapiInvestorFlags.SellTransactions ? null : i.SellTransactions
    }).AsEnumerable()
    .Select(e => e.i).FirstOrDefault();

我真的不知道为什么它不起作用。

I really can't tell why it does not work.

基本上是在我更改时:

i.Coins

i.Coins.Select(c => new { c, c.CoinType }).ToList()

它将停止工作。

推荐答案

您使用的技术并不是真正的显式加载( Include / ThenInclude ),但是基于投影和EF Core导航属性修复的技巧,所以我不能说为什么它停止工作。 EF Core仍然处理预测并包含不同的内容,因此它可能是当前处理中的缺陷。

The technique you are using is not really explicit loading (Include / ThenInclude), but trick based on projection and EF Core navigation property fix-up, so I can't say why it stops working. EF Core still processes projections and includes differently, so it might be a defect in the current processing.

在根查询级别实施条件包含相对容易。请注意, Include 方法从 IQueryable< TEntity> (已定义)开始,并返回 IIncludableQueryable< TEntity,TPreviousProperty>> 也是 IQueryable< TEntity> 。这意味着您可以保留 IQueryable< T> 查询变量,并应用类似于链式 Where 运算符的条件转换。

Implementing conditional include at the root query level is relatively easy. Note that the Include method starts from (is defined for) IQueryable<TEntity> and the returned IIncludableQueryable<TEntity, TPreviousProperty>> is also IQueryable<TEntity>. Which means you can keep IQueryable<T> query variable and apply conditional transformations similar to chained Where operators.

要使其更容易,您可以创建一个自定义帮助程序扩展方法,如下所示:

To make that easier, you could create a custom helper extension method like this:

public static IQueryable<T> If<T>(
    this IQueryable<T> source,
    bool condition,
    Func<IQueryable<T>, IQueryable<T>> transform
)
{ 
    return condition? transform(source) : source;
}

并像这样使用它:

_context.Investors.Where(s => s.Id == userId)
    .If(flagCoins, q => q.Include(e => e.Coins)
        .ThenInclude(e => e.CoinType))
    .If(flagBricks, q => q.Include(e => e.Bricks))

如果您需要类似的嵌套级别( ThenInclude ),然后添加以下2种扩展方法:

If you need something similar for the nested levels (ThenInclude), then add the following 2 extension methods:

public static IQueryable<T> If<T, P>(
    this IIncludableQueryable<T, P> source,
    bool condition,
    Func<IIncludableQueryable<T, P>, IQueryable<T>> transform
)
    where T : class
{
    return condition ? transform(source) : source;
}

public static IQueryable<T> If<T, P>(
    this IIncludableQueryable<T, IEnumerable<P>> source,
    bool condition,
    Func<IIncludableQueryable<T, IEnumerable<P>>, IQueryable<T>> transform
)
    where T : class
{
    return condition ? transform(source) : source;
}

这将允许您使用类似这样的东西:

which will allow you to use something like this:

_context.Investors.Where(s => s.Id == userId)
    .If(flagCoins, q => q.Include(e => e.Coins)
        .If(flagCoinType, q2 => q2.ThenInclude(e => e.CoinType)))
    .If(flagBricks, q => q.Include(e => e.Bricks))

这篇关于EF Core linq和条件包含然后包含问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆