Dot-Net

EF Core linq 和條件包含然後包含問題

  • July 6, 2020

嘗試獲取具有多個級別的對象時,我在獲取結果時遇到問題。這就是我要大致做的事情:

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

除了硬幣部分也有一個硬幣類型,所以我也需要包含它。但是當我添加我的程式碼時,整個部分停止工作。

這是我嘗試過的:

_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方法從 (is defined for) 開始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))

引用自:https://stackoverflow.com/questions/53474431