[英]Linq Query Optimization in Entity Framework
I have the following query, and what I'm looking for is to optimize the where
clause. 我有以下查询,我正在寻找的是优化where
子句。 I don't like the multiple FirstOrDefault
uses. 我不喜欢FirstOrDefault
的多种用法。 Is there a way to implement it with Join
maybe, or some other way so I will be able to access the FirstOrDefault
only once? 有没有可能用Join
或其他方法来实现它,这样我将只能访问一次FirstOrDefault
?
var promos = await this._context
.SinglePromotions
.Include(p => p.Rewards)
.Include(p => p.InAppProduct)
.Include(p => p.PlayerSinglePromotions)
.ThenInclude(sp => sp.Player)
.ThenInclude(pl => pl.Purchases)
.Where(p => p.MinimumPlayerLevel <= Player.Level &&
p.Placement == placement &&
p.IsActive &&
(p.PlayerSinglePromotions.All(sp => sp.PlayerID != Player.ID) ||
(p.PlayerSinglePromotions.FirstOrDefault(sp => sp.PlayerID == Player.ID).PurchaseAmount < p.PurchaseLimit)) &&
(p.PlayerSinglePromotions.All(sp => sp.PlayerID != Player.ID) || (p.PlayerSinglePromotions.FirstOrDefault(sp => sp.PlayerID == Player.ID).Player.Purchases.Count <= p.MaxInAppPurchasesByPlayer))
)
.ToListAsync();
Well, probably there is a better solution, but you could replace your conditions where you use FirstOrDefault
using Any
extension method instead: 好吧,也许有更好的解决方案,但是您可以使用Any
扩展方法替换使用FirstOrDefault
条件:
var promos = await this._context.SinglePromotions
.Include(p => p.Rewards)
.Include(p => p.InAppProduct)
.Include(p => p.PlayerSinglePromotions)
.ThenInclude(sp => sp.Player)
.ThenInclude(pl => pl.Purchases)
.Where(
p => p.MinimumPlayerLevel <= Player.Level &&
p.Placement == placement &&
p.IsActive &&
(p.PlayerSinglePromotions.All(sp => sp.PlayerID != Player.ID) ||
p.PlayerSinglePromotions.Any(sp => sp.PlayerID == Player.ID
&& (sp.Player.Purchases.Count <= p.MaxInAppPurchasesByPlayer || sp.PurchaseAmount < p.PurchaseLimit))))
.ToListAsync();
You can prevent repetition of long expression in LINQ queries by using query syntax with the let
clause . 通过使用带有let
子句的查询语法,可以防止LINQ查询中长表达式的重复。 It's like declaring variables that contain the result of an expression. 这就像声明包含表达式结果的变量一样。 In your query two parts are repeated that can be captured in let
variables: 在您的查询中,重复了两部分,可以在let
变量中捕获它们:
var promos = await (
from p in this._context.SinglePromotions
.Include(p => p.Rewards)
.Include(p => p.InAppProduct)
.Include(p => p.PlayerSinglePromotions)
.ThenInclude(sp => sp.Player)
.ThenInclude(pl => pl.Purchases)
let pspNotOfPlayer = p.PlayerSinglePromotions.All(sp => sp.PlayerID != Player.ID)
let firstPromotion = p.PlayerSinglePromotions.FirstOrDefault(sp => sp.PlayerID == Player.ID)
where
p.MinimumPlayerLevel <= Player.Level
&& p.Placement == placement
&& p.IsActive
&& pspNotOfPlayer || firstPromotion.PurchaseAmount < p.PurchaseLimit
&& pspNotOfPlayer || firstPromotion.Player.Purchases.Count <= p.MaxInAppPurchasesByPlayer
select p
)
.ToListAsync();
In many cases this will not only make the code more readable but also improve the generated SQL because repetitive subqueries can be replaced by CROSS APPLY
clauses. 在许多情况下,这不仅可以提高代码的可读性,而且可以改善生成的SQL,因为可以用CROSS APPLY
子句代替重复的子查询。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.