C# 使用多个子查询将LINQ重构为SQL/Entities查询
我有以下LINQ to Entities查询,它有许多子查询来获取一些聚合数据:C# 使用多个子查询将LINQ重构为SQL/Entities查询,c#,entity-framework,linq-to-sql,linq-to-entities,C#,Entity Framework,Linq To Sql,Linq To Entities,我有以下LINQ to Entities查询,它有许多子查询来获取一些聚合数据: var systems = from s in db.Systems orderby s.Name select new SystemSummary { Id = s.Id, Code = s.Code, Name = s.N
var systems = from s in db.Systems
orderby s.Name
select new SystemSummary
{
Id = s.Id,
Code = s.Code,
Name = s.Name,
LastException = (
from a in s.Applications
from e in a.Summaries
select e.CreationDate
).Max(),
TodaysExceptions = (
from a in s.Applications
from e in a.Summaries
where e.CreationDate >= today && e.CreationDate < tomorrow
select e
).Count(),
/* SNIP - 10-15 more subqueries */
};
我将查询缩短为只包含2个子查询,但可能还有10-15个子查询。有没有办法重构查询以清理代码?我不是在寻求业绩提升。我只想通过将子查询放入单独的方法来清理代码,同时确保它是对数据库的单个调用。这可能吗?将查询分为多个方法确实没有问题。但也有一些条件 确保您的查询是可计算的。这是默认设置 IEnumerable确保查询存储在变量中,但不执行。 编译器在运行时优化查询 又快又脏的例子:
private MyContext context = new MyContext()
private IEnumerable<User> getUser(Guid userID)
{
return context.User.Where(c => c.ID == userID);
}
private void evaluateUser()
{
bool isUserActive getUser().Any(c => c.IsActive)
}
您可以看到查询有两种方法。仍然只有一个对DB的调用,因为IEnumerable存储查询而不是结果。只有在需要时才执行查询。我可以通过在原始查询中使用关键字来最小化其长度:
var subQuery = from a in s.Applications
from e in a.Summaries
select e;
您还可以进行一些重构,如:
subQuery.Count(e=>e.CreationDate >= today && e.CreationDate < tomorrow);
subQuery.max(e=>e.CreationDate);
这仍然是对DB的单一调用。
您可能想考虑使用LET关键字来创建查询的本地变量,这最终会成为您的子查询。例如:var systems = from s in db.Systems
orderby s.Name
let lastException = (from a in s.Applications from e in a.Summaries select e.CreationDate).Max()
...
您可以做的另一个选择可能是立即从各种关联创建一个子查询,并使用这些元素
var systems = from s in db.Systems
orderby s.Name
from summaries in
(from ta in s.Applications
from te in ta.Summaries
...
select { APPS = ta, SUMMS = te ,/*anything else you want*/ })
let lastExpire = (from summaries select SUMMS.CreationDate).Max()
见鬼,在第二个示例中,您甚至可以只保留let,而在最终选择中使用summaries实体。您可能需要对其进行一些处理,以确保不会得到任何重复的值,但至少通过这种方式,您可以直接对摘要进行选择,而不是每次都重写子查询。如果您想要更干净的代码,您可能需要考虑在您的内存中创建存储过程。database@Mathieu这是唯一的办法吗?我想你是说我可以,而不是我可以。IEnumerable将使其将查询转换为内存中的对象。@Dismissile,我错过了s,我编辑了答案,您可以使用let在查询中模拟这种方式。希望这有帮助,也很高兴看到您的评论:
var systems = from s in db.Systems
orderby s.Name
from summaries in
(from ta in s.Applications
from te in ta.Summaries
...
select { APPS = ta, SUMMS = te ,/*anything else you want*/ })
let lastExpire = (from summaries select SUMMS.CreationDate).Max()