2014-05-16 215 views
0

我有一個用戶表,分組到會話中。我想選擇一個陣列對於由多項任務的每個用戶他們在每一屆有:LINQ to SQL:在一個查詢中選擇整數數組

var taskCounts = 
    from session in gzClasses.e_userLongSessions 
    orderby session.workerId ascending, session.startTime ascending 
    group session by session.workerId 
    into record 
    select record.Select(s => s.totalTasks).ToArray(); 
int[][] result = taskCounts.ToArray(); 

上述理論上的作品,但它導致在一個單獨的SQL查詢爲每個用戶如下圖所示。由於數據庫不是本地的,這需要相當長的時間。有沒有辦法在一個查詢中獲取所有數據,並減少運行大量單個查詢的開銷?

enter image description here

同時,我想確保它僅通過線路傳輸totalTasks整數值,而不是發送整個數據庫記錄的效率。換句話說,我想從一個遠程數據庫中獲取一組分組整數,並將它們排列成C#程序中的數組。這聽起來很簡單,但我很難讓LINQ來做到這一點。

+0

您的ef上下文中是否啓用了延遲加載?這可以解釋這樣的行爲,因爲對於每個將被枚舉的對象,它將執行不同的查詢。 –

+0

@DimitrisKalaitzis我不知道那是什麼 - 你能給一個指示器顯示如何關閉它,我會再次嘗試這個查詢嗎? –

+0

你使用實體框架嗎?如果你確實可以改變你設置gzClasses的設置。例如gzClasses.ContextOptions.LazyLoadingEnabled = false; –

回答

1

取決於你有多少條記錄回來,你可以返回最小的數據量,並在內存中做分組部(很快,因爲它會已進行排序):

使用方法的語法:

gzClasses.e_userLongSessions 
     .OrderBy(s => s.workerId) 
     .ThenBy(s => s.startTime) 
     .Select(s => new { s.workerId, s.totalTasks }) 
     .ToList() 
     .GroupBy(x => x.workerId) 
     .Select(g => g.Select(x => x.totalTasks).ToArray()) 
     .ToArray(); 

使用查詢語法:

var query = from session in gzClasses.e_userLongSessions 
      orderby session.workerId ascending, session.startTime ascending 
      select new { Id = s.workerId, s.totalTasks }; 

var taskCounts = from worker in query.ToList() 
       group worker by worker.Id into g 
       select g.Select(x => x.totalTasks).ToArray(); 

var result = taskCounts.ToArray(); 

我看到Linqpad(LINQ到SQL默認)相同的行爲,但我覺得好像我見過的LINQ到實體處理GroupBy然後是group.Select(x => x.Something)而不會導致n + 1查詢......可能是想象的東西,雖然(不知道SQL看起來會達到什麼樣的)。

+0

是的,在內存中執行此操作可能是一種很好的解決方法。這是LINQ到SQL,我相信(雖然我不熟悉Windows的術語)。我也不知道SQL會怎樣做,所以這可能是正確的方法,除非有人提出了一些我不知道的魔法。 –

+0

優秀。這個查詢幾乎是即時的,但我不得不編輯你的答案。你能否看看是否有更簡潔的方式來編寫上面的語法?你的回答不完全正確,因爲你需要抓住'g.Select(e => e.totalTask​​s).toArray()'。 –

+0

正如我在之前的編輯中提到的那樣,在將其轉換爲數組之前,您需要在某個時間點將'totalTask​​s'字段從分組中取出,否則它將不是'int [] []'。 –

-2

您的ToArray()的位置會導致LINQ比應該更加渴望,導致您的許多查詢。我認爲,這將導致在短短的一個查詢:

var taskCounts = 
    from session in gzClasses.e_userLongSessions 
    orderby session.workerId ascending, session.startTime ascending 
    group session by session.workerId 
    into record 
    select record.Select(s => s.totalTasks); 
int[][] result = taskCounts.Select(x => x.ToArray()).ToArray(); 
+0

您的查詢在功能上與OP的查詢完全相同。 – Servy

+0

'Select'仍然在'IQueryable'上,可能會產生他看到的相同結果。 taskCounts.ToList()。選擇(x => x.ToArray())。ToArray()'可能會做到這一點。 – Ocelot20

+0

這實際上會導致相同的行爲,因爲我認爲它在功能上是相同的查詢。在調用'toArray'之前,'IQueryable'不會被評估,所以構造方法並不重要。 –

-1

也許如果你更換「從會議gzClasses.e_userLongSessions」,由「從gzClasses.e_userLongSessions.AsEnumerable()會議」?

+0

如何不在數據庫上執行任何*查詢以確保在數據庫上執行* entire *查詢? – Servy

+0

我不明白這是幹什麼的,因爲它將IQueryable轉換爲IEnumerable,如果有的話,它基本上會通過線路拉動整個數據庫來回答查詢。 –

+0

完全安德魯,它會帶來來自gzClasses.e_userLongSessions的所有記錄,但無論如何,這個組......通過...進入不像SQL組那樣,SQL沒有一個命令來組成一個列表中,EF將其轉換爲SQL命令的方式是向每個workerId發出一個select,將所有記錄帶入多個SELECT中,而不是將所有記錄都放入一個SELECT中,並使.Net執行此操作。順便說一句AsEnumerable的工作? – EduardoS

0

字典不會比數組數組更有用嗎?

gzClasses.e_userLongSessions.OrderBy(s => s.workerId) 
    .ThenBy(s => s.startTime) 
    .GroupBy(s => s.workerId, t => t.TotalTasks).ToArray() 
    .ToDictionary(g => g.Key, h => h.ToArray()); 

這應該返回一個以workerId爲關鍵字的Dictionary和一個任務數量數組作爲值。

+0

我認爲這同樣有效,但它並不真正回答原始問題。或者,至少,它隱含地做着@ Ocelot20的回答,把所有內容都放在第一位。 –

+0

這是一個LINQ to SQL如何實現的問題,並不是您可以輕鬆解決的問題。最好的方法是強制執行初始語句,然後將數據分組到內存中。 EF中的實施似乎更適合您的需求。 http://stackoverflow.com/questions/12645767/linq-to-sql-simple-group-by-generating-many-sql-queries – user1417835

+0

我不認爲我完全掌握了LINQ to SQL和實體之間的區別框架。我將不得不再看看更多。 –