2011-08-29 29 views
5

我有一個表,可以稱之爲Record。包含: ID(int)| CustID(int)|時間(日期時間)|數據(VARCHAR)C#LINQ查詢(MYSQL EF) - 獨特和最新記錄

我需要爲每個客戶的最新(最近)的記錄:

SQL

select * from record as i group by i.custid having max(id); 

LINQ版本1

dgvLatestDistinctRec.DataSource = from g in ee.Records 
            group g by g.CustID into grp 
            select grp.LastOrDefault(); 

這將引發錯誤:

System.NotSupportedException was unhandled by user code Message=LINQ to Entities does not recognize the method 'Faizan_Kazi_Utils.Record LastOrDefault[Record ](System.Collections.Generic.IEnumerable`1[Faizan_Kazi_Utils.Record ])' method, and this method cannot be translated into a store expression. Source=System.Data.Entity

LINQ版本2

var list = (from g in ee.Records 
      group g by g.CustID into grp 
      select grp).ToList(); 
Record[] list2 = (from grp in list 
        select grp.LastOrDefault()).ToArray(); 
dgvLatestDistinctRec.DataSource = list2; 

這工作,但效率很低,因爲它從數據庫加載到內存中的所有記錄,然後提取剛剛過去的(最新成員)各組。

是否有任何LINQ解決方案接近所提到的SQL解決方案的效率和可讀性?

+0

您是如何實現Mysql + LINQ的。 DBSet是否支持Mysql?如果是這樣,你可以說怎麼樣?我渴望達到這個目標,並在上週放棄了。 – prabhakaran

+0

我只需要核心點,至少在你放置連接字符串的地方。 – prabhakaran

回答

4

更新:

var results = (from rec in Record group rec by rec.CustID into grp 
    select new 
    { 
     CustID = grp.Key, 
     ID = grp.OrderByDescending(r => r.ID).Select(x => x.ID).FirstOrDefault(), 
     Data = grp.OrderByDescending(r => r.ID).Select(x => x.Data).FirstOrDefault() 
    } 
); 

所以我做了一個測試表,並寫了一個LINQ - > SQL查詢,會做正是你需要的。看看這個,讓我知道你的想法。唯一要記住的是,如果這個查詢是縮放的,我相信它會在select new中的分組後對每個CustID記錄運行一次對數據庫的查詢。可以肯定的唯一方法是運行SQL跟蹤程序,當你上到這裏運行查詢信息.. http://www.foliotek.com/devblog/tuning-sql-server-for-programmers/

原文:

你能不能做這樣的事? from g in ee.Records where g.CustID == (from x in ee.Records where (g.CustID == x.CustID) && (g.ID == x.Max(ID)).Select(r => r.CustID))

這都是僞代碼,但希望你能明白這一點。

+0

好的,所以我嘗試了你所說的,並在兩個輪子上給出了錯誤:Delegate System.Func '不接受1個參數 –

+0

和在ID(ID)中給出:在當前上下文中不存在名稱'id' –

+0

我得到你想要做的,但我一直無法做出所需的更改以使其工作:s –

1

我認爲grp.LastOrDefault()是一個C#函數,它是SQL不知道的。 LINQ將您的查詢轉換爲您的數據庫服務器要理解的SQL查詢。您可能想嘗試創建存儲過程,或者使用其他方法來篩選出您所需要的內容。

您的第二個查詢工作原因是因爲LINQ to SQL返回一個列表,然後在C#列表中執行LINQ查詢(篩選出您需要的),該列表實現了IEnumerable/IQueryable接口並理解grp .LastOrDefault()。

+0

True,LastOrDefault未在MySQL實體框架提供程序中實現(如錯誤所示)。 –

+0

是的,它會返回一個長列表作爲內存集合,然後每個CustID過濾掉單個條目,這對於內存和處理器使用情況來說並不理想。這就是爲什麼我在這裏尋求幫助:) –

1

如果用簡單的Last()替換LastOrDefault()會怎麼樣? (是的,你將不得不檢查你的記錄表是不是空的)

因爲我看不到MySQL如何返回你的「默認」組。這不是可以簡單地轉換爲SQL的東西。

+0

當我使用最後我得到這個錯誤:System.NotSupportedException被用戶代碼未處理 消息= LINQ到實體無法識別方法'Faizan_Kazi_Utils.Record最後[記錄](系統.Collections.Generic.IEnumerable'1 [Faizan_Kazi_Utils.Record])'方法,並且此方法不能被轉換爲商店表達式。 Source = System.Data.Entity –

0

我有另一個想法:

// Get a list of all the id's i need by: 
// grouping by CustID, and then selecting Max ID from each group. 
var distinctLatest = (from x in ee.Records 
          group x by x.CustID into grp 
          select grp.Max(g => g.id)).ToArray(); 

// List<Record> result = new List<Record>(); 

//now we can retrieve individual records using the ID's retrieved above 
// foreach (int i in distinctLatest) 
// { 
// var res = from g in ee.Records where g.id == i select g; 
// var arr = res.ToArray(); 
// result.Add(res.First()); 
// } 

// alternate version of foreach 
dgvLatestDistinctRec.DataSource = from g in ee.Records 
              join i in distinctLatest 
              on g.id equals i 
              select g; 
+0

這是有點基於bigamils解決方案...它在我的腦海中產生了這種思想流 –

+0

你真的不想這樣做.ToArray()或ToList(),因爲這將返回所有記錄並將它們放入記憶。你希望Linq - > SQL來完成所有的工作。基本上它構建了一個動態表達式樹,在你請求一個值之前,它並沒有真正執行任何SQL。關鍵的東西,請求瓦爾(ToList(),ToArray(),First(),Last()等)抱歉,如果我是多餘的。無論如何更新我的答案,以做到你所需要的。如果它適合您,請將我的評價/標記爲答案!希望這有幫助 – bigamil

+0

嗯......但第一個.ToArray只是加載一對夫婦整數內存(獨特的客戶ID),然後第二個正是我所需要的(加載整個記錄:每個不同客戶的最新記錄) ...不好嗎? –

2

我可能爲時已晚,以幫助您的問題,但我也有類似的問題,並能夠與這樣的查詢,以獲得期望的結果:

from g in ee.Records 
group g by g.CustID into grp 
from last in (from custRec in grp where custRec.Id == grp.Max(cr => cr.Id) select custRec) 
select last 
+0

這太棒了。 .. 很好的表現! –