是否有一种使用查询语法在LINQ查询中执行ToList的简洁方法?

Geo*_*ett 12 c# linq syntax readability linq-to-sql

请考虑以下代码:

StockcheckJobs = 
     (from job in (from stockcheckItem in MDC.StockcheckItems
                   where distinctJobs.Contains(stockcheckItem.JobId)
                   group stockcheckItem by new { stockcheckItem.JobId, stockcheckItem.JobData.EngineerId } into jobs
                   select jobs).ToList()
      let date = MJM.GetOrCreateJobData(job.Key.JobId).CompletedJob.Value
      orderby date descending 
      select new StockcheckJobsModel.StockcheckJob()
      {
          JobId = job.Key.JobId,
          Date = date,
          Engineer = (EngineerModel)job.Key.EngineerId,
          MatchingLines = job.Count(sti => sti.Quantity == sti.ExpectedQuantity),
          DifferingLines = job.Count(sti => sti.Quantity != sti.ExpectedQuantity)
      }).ToList()
Run Code Online (Sandbox Code Playgroud)

ToList()中间有一个因为该GetOrCreateJobData方法无法转换为sql.

因此,我必须用括号括起我的查询的第一部分来执行此操作,然后我使用外部查询来完成.

我知道我可以把它分成两个变量,但我不想这样做(这也是在一个对象初始化器中).

有什么其他语法我可以用来增加可读性,最好不需要外部内部查询,当我必须ToList在linq查询中间做一个(或以其他方式获取linq到对象)?


在一个理想的世界里,我喜欢这样的东西(尽可能接近):

StockcheckJobs =
     from stockcheckItem in MDC.StockcheckItems
     where distinctJobs.Contains(stockcheckItem.JobId)
     group stockcheckItem by new { stockcheckItem.JobId, stockcheckItem.JobData.EngineerId } into jobs
     MAGIC_DO_BELOW_AS_LINQ-TO-OBJECTS_KEYWORD_OR_SYNTAX
     let date = MJM.GetOrCreateJobData(jobs.Key.JobId).CompletedJob.Value
     orderby date descending 
     select new StockcheckJobsModel.StockcheckJob()
     {
         JobId = jobs.Key.JobId,
         Date = date,
         Engineer = new ThreeSixtyScheduling.Models.EngineerModel() { Number = jobs.Key.EngineerId },
         MatchingLines = jobs.Count(sti => sti.Quantity == sti.ExpectedQuantity),
         DifferingLines = jobs.Count(sti => sti.Quantity != sti.ExpectedQuantity)
     };
Run Code Online (Sandbox Code Playgroud)

sma*_*man 5

您可以解决GetOrCreateJobData不能转换为SQL的问题.

通过为指定的方法调用表达式实现自定义查询转换器,您可以控制LINQ-to-SQL如何解释该方法.有一篇很好的文章解释了这个程序,并链接到相关资源:http://www.codeproject.com/Articles/32968/QueryMap-Custom-translation-of-LINQ-expressions

或者,您可以将GetOrCreateJobData方法重构为扩展方法,该方法使用表达式构建相同的逻辑,以便LINQ-to-SQL可以自然地解释它.根据方法的复杂程度,这可能比我的第一个建议或多或少可行.


Ani*_*Ani 3

对于这个问题我想提出两点:

  1. 我真的不认为在这里引入额外的变量有任何可读性问题。事实上,我认为这使得它更具可读性,因为它将“本地执行”代码与在数据库上执行的代码分开。
  2. 简单地切换到 LINQ-To-ObjectsAsEnumerableToList.

也就是说,以下是如何在整个查询表达式上无需中间 AsEnumerable() / ToList() 即可始终保持查询状态的方法:欺骗 C# 编译器使用自定义扩展方法而不是 BCL。这是可能的,因为 C# 使用“基于模式”的方法(而不是与 BCL 耦合)将查询表达式转换为方法调用和 lambda。

声明如下邪恶类:

public static class To
{
    public sealed class ToList { }

    public static readonly ToList List;

    // C# should target this method when you use "select To.List"
    // inside a query expression.
    public static List<T> Select<T>
        (this IEnumerable<T> source, Func<T, ToList> projector)
    {
        return source.ToList();
    }
}

public static class As
{
    public sealed class AsEnumerable { }

    public static readonly AsEnumerable Enumerable;

    // C# should target this method when you use "select As.Enumerable"
    // inside a query expression.
    public static IEnumerable<T> Select<T>
        (this IEnumerable<T> source, Func<T, AsEnumerable> projector)
    {
        return source;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你可以编写这样的查询:

List<int> list = from num in new[] { 41 }.AsQueryable()
                 select num + 1 into result
                 select To.List;

IEnumerable<int> seq = from num in new[] { 41 }.AsQueryable()
                       select num + 1 into result
                       select As.Enumerable into seqItem
                       select seqItem + 1; // Subsequent processing
Run Code Online (Sandbox Code Playgroud)

在您的情况下,您的查询将变为:

StockcheckJobs =
     from stockcheckItem in MDC.StockcheckItems
     where distinctJobs.Contains(stockcheckItem.JobId)
     group stockcheckItem by new { stockcheckItem.JobId, stockcheckItem.JobData.EngineerId } into jobs
     select As.Enumerable into localJobs // MAGIC!
     let date = MJM.GetOrCreateJobData(localJobs.Key.JobId).CompletedJob.Value
     orderby date descending 
     select new StockcheckJobsModel.StockcheckJob()
     {
         JobId = localJobs.Key.JobId,
         Date = date,
         Engineer = new ThreeSixtyScheduling.Models.EngineerModel() { Number = localJobs.Key.EngineerId },
         MatchingLines = localJobs.Count(sti => sti.Quantity == sti.ExpectedQuantity),
         DifferingLines = localJobs.Count(sti => sti.Quantity != sti.ExpectedQuantity)
     };
Run Code Online (Sandbox Code Playgroud)

不过,我真的不认为这有任何改进。相反,这是对语言功能的严重滥用。