[英]EF Core linq and conditional include and theninclude problem
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();
This works except that the Coins section also has a cointype in it so I need to include it too.除了 Coins 部分也有一个硬币类型,所以我也需要包括它。 But when I add my code, the whole section stops working.
但是当我添加我的代码时,整个部分停止工作。
This is what I tried:这是我尝试过的:
_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.我真的不知道为什么它不起作用。
Basically when I change:基本上当我改变时:
i.Coins
To到
i.Coins.Select(c => new { c, c.CoinType }).ToList()
it stops working.它停止工作。
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.您使用的技术并不是真正的显式加载(
Include
/ ThenInclude
),而是基于投影和 EF Core 导航属性修复的技巧,所以我不能说它为什么停止工作。 EF Core still processes projections and includes differently, so it might be a defect in the current processing. EF Core 仍然以不同方式处理投影和包含,因此它可能是当前处理中的缺陷。
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>
.请注意,
Include
方法从(定义为) IQueryable<TEntity>
,返回的IIncludableQueryable<TEntity, TPreviousProperty>>
也是IQueryable<TEntity>
。 Which means you can keep IQueryable<T>
query variable and apply conditional transformations similar to chained Where
operators.这意味着您可以保留
IQueryable<T>
查询变量并应用类似于链式Where
运算符的条件转换。
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;
}
and use it like this:并像这样使用它:
_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))
If you need something similar for the nested levels ( ThenInclude
), then add the following 2 extension methods:如果您需要类似的嵌套级别 (
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;
}
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))
you can use my extension method.你可以使用我的扩展方法。
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.