繁体   English   中英

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

[英]EF Core linq and conditional include and theninclude problem

尝试获取具有多个级别的对象时,我在获取结果时遇到问题。 这就是我想要粗略地做的事情:

_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.

基本上我得到了很多标志,表明我是否应该包含对象的一部分。 我几乎可以工作了。 像这样:

_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 部分也有一个硬币类型,所以我也需要包括它。 但是当我添加我的代码时,整个部分停止工作。

这是我尝试过的:

_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.Coins

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

它停止工作。

您使用的技术并不是真正的显式加载( 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;
}

并像这样使用它:

_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 个扩展方法:

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;
}

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

_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))

你可以使用我的扩展方法。

  1. 使用:
 var filteredTransactions = _transactionRepository.GetAll()
                    .Where(x => x.CreationTime.Ticks <= input.FetchingTikes)
                    .IncludeIf(input.Filter.IsNotNullOrWhitespace(), t => t.DestinationAccountFk.Merchant, t => t.SourceAccountFk.UserFk)
  1. 扩展:
 public static IQueryable<TEntity> IncludeIf<TEntity>([NotNull] this 
   IQueryable<TEntity> source
                ,bool condition
                ,params Expression<Func<TEntity, object>>[] 
    navigationPropertyPaths)
                where TEntity : class
            {
                if (condition)
                {
                    if (navigationPropertyPaths.IsNotNullOrEmpty())
                    {
                        foreach (var navigationPropertyPath in 
   navigationPropertyPaths)
                        {
                            source = source.Include(navigationPropertyPath);
                        }
                    }
                }
                return source;
            }
  1. 其他扩展:
        public static bool IsNotNullOrEmpty<T>(this IEnumerable<T> list)
        {
            if (list.IsNotNull() && list.IsNotEmpty())
            {
                return true;
            }
            return false;
        }

        public static bool IsNotNull(this object obj)
        {
            if (obj != null)
            {
                return true;
            }
            return false;
        }

        public static bool IsNotEmpty<T>(this IEnumerable<T> list)
        {
            if (list.Count() > 0)
            {
                return true;
            }
            return false;
        }



       

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM