[英]How Include / ThenInclude in EF Core 3.1 Will Be transformed as Inner Join
[英]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))
你可以使用我的擴展方法。
var filteredTransactions = _transactionRepository.GetAll()
.Where(x => x.CreationTime.Ticks <= input.FetchingTikes)
.IncludeIf(input.Filter.IsNotNullOrWhitespace(), t => t.DestinationAccountFk.Merchant, t => t.SourceAccountFk.UserFk)
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;
}
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.