EF Core linq和条件包含然后包含问题

zaw*_*sza 6 .net entity-framework entity-framework-core .net-core

尝试获取具有多个级别的对象时,无法获得结果。这是我正在尝试大致执行的操作:

_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.
Run Code Online (Sandbox Code Playgroud)

本质上,我会收到很多标志,指示是否应包括对象的一部分。我几乎要工作了。像这样:

_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();
Run Code Online (Sandbox Code Playgroud)

除硬币部分中也有硬币类型外,此方法有效,因此我也需要包括它。但是,当我添加代码时,整个部分将停止工作。

这是我尝试的:

_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();
Run Code Online (Sandbox Code Playgroud)

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

基本上,当我改变时:

i.Coins
Run Code Online (Sandbox Code Playgroud)

i.Coins.Select(c => new { c, c.CoinType }).ToList()
Run Code Online (Sandbox Code Playgroud)

它停止工作。

Iva*_*oev 14

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

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

为了简化操作,您可以创建一个自定义帮助程序扩展方法,如下所示:

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

并像这样使用它:

_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))
Run Code Online (Sandbox Code Playgroud)

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

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;
}
Run Code Online (Sandbox Code Playgroud)

这将使您可以使用以下内容:

_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))
Run Code Online (Sandbox Code Playgroud)

  • 非常感谢。这比我正在做的要好得多。 (2认同)
  • 流畅的实现。完美运作。 (2认同)
  • 这很棒,但为什么它没有内置到 EF 核心中? (2认同)