Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/entity-framework/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用多个子查询将LINQ重构为SQL/Entities查询_C#_Entity Framework_Linq To Sql_Linq To Entities - Fatal编程技术网

C# 使用多个子查询将LINQ重构为SQL/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

我有以下LINQ to Entities查询,它有许多子查询来获取一些聚合数据:

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