构建LINQ表达式被忽略

时间:2015-06-20 15:21:57

标签: linq

我正在尝试从客户端构建来自表格网格的linq查询,因此我期待页面偏移,页面开始,顺序和传统的分页参数。我有以下代码:

  [Route("api/settings/logs")]
   public Rest.DatatablesResponse GetLogs(int draw, int start, int length) {

       var query_string = Request.GetQueryNameValuePairs().ToDictionary(x => x.Key, x => x.Value);
       var search = query_string["search.value"];

       int order_column = int.Parse(query_string["order[0].column"]);
       var order_direction = query_string["order[0].dir"];

       var count = db.Logs.Count(q => q.Mode == 2);
       var logs = (from l in db.Logs
                   where l.Mode == 2
                   select new {
                       id = l.ID,
                       mode = l.Mode,
                       phase_id = l.Phase.ID,
                       created = l.Created,
                       user = l.User.Name,
                       blender_name = l.Blender.Name,
                       oil_name = l.Oil,
                       oil_quantity = l.OilQuantity,
                       production_cycle_name = l.ProductionCycle.Name
                   });

       if (order_direction == "asc") {
           if (order_column == 0) logs.OrderBy(q => q.created);
           else if (order_column == 2) logs.OrderBy(q => q.production_cycle_name);
       } else {
           if (order_column == 0) logs.OrderByDescending(q => q.created);
           else if (order_column == 2) logs.OrderByDescending(q => q.production_cycle_name);
       };

       if (!string.IsNullOrEmpty(search)) {
           logs.Where(q => q.blender_name.Contains(search) ||
                      q.oil_name.Contains(search) ||
                      SqlFunctions.StringConvert((decimal)q.id).Contains(search));
       }

      logs.Skip(start).Take(length);




        DateTime dtDateTime = new DateTime(1970,1,1,0,0,0,0,System.DateTimeKind.Utc);


        var steps = from l in logs.ToList()
                   select new {
                      id = l.id,
                      message = StringHelpers.FormatWith(_tpl_message[l.phase_id.ToString() +  l.mode.ToString() ], l) ,
                      created = dtDateTime.AddSeconds(l.created).ToString("h:mmtt - MMMM d, yyyy"),     
                      production_cycle_name = l.production_cycle_name
                   };

       return new Rest.DatatablesResponse {
           draw = draw,
           recordsTotal = count,
           recordsFiltered = count,
           data = steps.ToArray()
       };
   }

我的问题是skip和take和orderby表达式由于某种原因被忽略,这是在将我的linq表达式转换为列表之前生成的SQL代码。根据我的理解,在我的logs.ToList()调用之前不应该执行或评估查询,因此应该考虑排序和take / skip,但它不是:

{SELECT 
    [Extent1].[ID] AS [ID], 
    [Extent1].[Mode] AS [Mode], 
    [Extent1].[Phase_ID] AS [Phase_ID], 
    [Extent1].[Created] AS [Created], 
    [Extent2].[Name] AS [Name], 
    [Extent3].[Name] AS [Name1], 
    [Extent1].[Oil] AS [Oil], 
    [Extent1].[OilQuantity] AS [OilQuantity], 
    [Extent4].[Name] AS [Name2]
    FROM    [dbo].[Steps] AS [Extent1]
    LEFT OUTER JOIN [dbo].[Users] AS [Extent2] ON [Extent1].[User_Id] = [Extent2].[Id]
    LEFT OUTER JOIN [dbo].[Blenders] AS [Extent3] ON [Extent1].[Blender_ID] = [Extent3].[ID]
    LEFT OUTER JOIN [dbo].[ProductionCycles] AS [Extent4] ON [Extent1].[ProductionCycle_ID] = [Extent4].[ID]
    WHERE 2 = [Extent1].[Mode]}

不相关的P.S。我使用不那么聪明的ifs来构建订单表达式而不是使用DynamicLINQ,因为我只有两个可排序的列。

1 个答案:

答案 0 :(得分:1)

logs.Skip(start).Take(length);

创建IQueryable<T>,其中T是相同的匿名类型,logsIQueryable<T>但跳过start项。然后,它会创建一个类似的IQueryable<T>,其中lenght个项目将是最多的。

然后它扔掉它并让它被垃圾收集。 (或者理想情况下,编译器或抖动步骤会意识到它被抛弃并切断整个事物)。

然后logs.ToList()返回到您仍然拥有的logs并从中创建一个列表。

您应该将SkipTake行替换为:

logs = logs.Skip(start).Take(length);

因此,您实际上正在利用此跳过和拍摄。

  

我使用不那么聪明的ifs来构建订单表达式而不是使用DynamicLINQ,因为我只有两个可排序的列。

除了犯同样的错误外,没有什么特别不聪明的事情;应用OrderBy,然后丢弃结果而不是使用它。与Where相同。您需要logs = logs.OrderBy(...)等。

我也在这里问from l in logs.ToList() select new {…}

这可能是最好的方法,如果一步获得该列表有一些优势。不然的话:

from l in logs select new {…}

select是否适用于数据库,只检索您需要的内容。

from l in logs.AsEnumerable() select new {…}

select在应用程序中是否正常工作,如果它的一部分无法转换为数据库工作,那么它是适当的,但是在它来的时候这样做而不是先将它全部加载到内存中。

from l in await logs.ToListAsync() select new {…}

ToList()的缺点,但在异步使用中,(假设您的提供商使用ToListAsync()方法)允许await

ToList()很少是最好的选择。