2015-06-20 67 views
0

我想從客戶端來的表格網格建立一個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() 
     }; 
    } 

我的問題是跳躍,並採取和排序依據表達式得到某種原因被忽略,而這僅僅是我的轉化LINQ表達式到列表之前生成的SQL代碼。從我的理解,查詢應不執行或評估直到我logs.ToList()調用,因此訂貨,並採取/跳過,應考慮到,但它不是:

{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]} 

無關附:我使用不那麼聰明的ifs來構建順序表達式,而不是使用DynamicLINQ,因爲我只有兩個可排序的列。

回答

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 ING。

ToList()很少是這裏最好的選擇。

+0

非常感謝,我雖然.Skip的作品就像在哪裏它不創建一個新的實例。我沒有在我的代碼中擁抱整個異步的東西,但看起來我很快會從你的答案 –

+0

'Skip()'像'.Where()'那樣工作**創建一個新實例。所有這些方法都會創建一個新的輕量級實例,它本身是不可變的,因此無法更改。 –