iT邦幫忙

0

LINQ FirstOrDefault() 與LastOrDefault()問題

請教各位大大
我寫了以下lambda搜尋式LastOrDefault(),改寫了各式各樣的方式,一直報錯。

int Revision = db.PaperFiles.Where(p => p.PaperId == PaperId && p.MemberId == MemberId && p.SubmittedType == submittedType && p.Stage == 2).LastOrDefault().Revision;

VS Error Message 使用者程式碼末處理NotSupportedException

'System.NotSupportedException' 類型的例外狀況發生於 EntityFramework.SqlServer.dll,但使用者程式碼未加以處理

其他資訊: LINQ to Entities 無法辨識方法 'Submission1.Areas.Users.Models.PaperFile LastOrDefault[PaperFile](System.Linq.IQueryable`1[Submission1.Areas.Users.Models.PaperFile])' 方法,而且這個方法無法轉譯成存放區運算式。

最後測試碼發現竟然是因為LastOrDefault()的問題,改寫FirstOrDefault()就過了,實在不懂為什麼會這樣,上來請教一下各位大師~

int Revision = db.PaperFiles.Where(p => p.PaperId == PaperId && p.MemberId == MemberId && p.SubmittedType == submittedType && p.Stage == 2).OrderByDescending(d => d.UploadDate).Select(f => f.Revision).FirstOrDefault();

謝謝指教

1 個回答

0
小魚
iT邦大師 1 級 ‧ 2019-08-09 16:33:38
最佳解答

你上面和下面寫的不一樣啊 XD
一個是

LastOrDefault().Revision;

一個是

FirstOrDefault();
看更多先前的回應...收起先前的回應...
leo226 iT邦新手 4 級 ‧ 2019-08-09 17:42:59 檢舉

小魚大師,應該說我寫LastOrDefault()都出現Error(試了多種LastOrDefault()的寫法),但改成FirstOrDefault()就沒有發生Error了。但不知道為什麼用LastOrDefault()就會Error

小魚 iT邦大師 1 級 ‧ 2019-08-09 18:10:01 檢舉

我試過 LastOrDefault 本身是沒有問題的,
你確定你把LastOrDefault後面的 Revision 拿掉不能用嗎?

leo226 iT邦新手 4 級 ‧ 2019-08-09 21:15:44 檢舉

魚大,我又測試了一次,我很確定喔,執行結果如圖所示

執行程式碼如下

int Revision = db.PaperFiles.Where(p => p.PaperId == PaperId && p.MemberId == MemberId && p.SubmittedType == submittedType && p.Stage == 2).Select(f => f.Revision).LastOrDefault();

//int Revision = db.PaperFiles.Where(p => p.PaperId == PaperId && p.MemberId == MemberId && p.SubmittedType == submittedType && p.Stage == 2).OrderByDescending(d => d.UploadDate).Select(f => f.Revision).FirstOrDefault();

實在搞不懂為什麼FirstOrDefault就可以,LastOrDefault就Error

小魚 iT邦大師 1 級 ‧ 2019-08-09 21:30:48 檢舉

好像也有人遇到 這個問題
不過說真的SQL好像也沒有在取Last的,
都是從First開始...

既然日期由大往小排(DESC)取最後一個不能用
那跟從小往大排(ASC)取第一個,不是一樣的意思?

int Revision = 
    db.PaperFiles
        .Where(p => 
                p.PaperId == PaperId && 
                p.MemberId == MemberId && 
                p.SubmittedType == submittedType &&
                p.Stage == 2)
        .OrderBy(d => d.UploadDate)
        .Select(f => f.Revision)
        .FirstOrDefault();

(我還是習慣縮排一下,才看的懂階層關係)

小魚 iT邦大師 1 級 ‧ 2019-08-10 14:00:01 檢舉

結果是一樣的,
但奇檬子不一樣啊
/images/emoticon/emoticon39.gif

fillano iT邦超人 1 級 ‧ 2019-08-10 19:27:02 檢舉

兩段程式碼還是不一樣阿,FirstOrDefault的有OrderByDescending。

另外:https://stackoverflow.com/questions/7293639/linq-to-entities-does-not-recognize-the-method-last-really

主要是TSQL語法有Top但是沒有Last,不過其他家Provider有可能支援Last/LastOrDefault。

小魚 iT邦大師 1 級 ‧ 2019-08-10 22:03:17 檢舉

說到這個,
如果你轉成List再LastOrDefault可以嗎?
我之前測試是用List去做LastOrDefault的...

fillano iT邦超人 1 級 ‧ 2019-08-11 11:46:47 檢舉

Linq to Entities轉成List時會Materialize,也就是產生SQL並查詢,然後再把查詢結果轉成List。之後呼叫LastOrDefault就跟SQL沒關係了。

leo226 iT邦新手 4 級 ‧ 2019-08-12 10:25:17 檢舉

回覆各位大大:
japhenchen意思是一樣的我知道,一開始直覺直接用LastOrDefault,結果無法執行,改成FirstOrDefault,只是把問題提出來,如果以後想用LastOrDefault就不會遇到同樣問題了~
小魚fillano大大,測試轉成List再LastOrDefault這樣就可以用了,感謝解答~

leo226 iT邦新手 4 級 ‧ 2019-08-12 10:29:36 檢舉

然後更正japhenchen大的說明,我要取日期最大的,所以應該是:
既然從小往大排(ASC)取最後一個不能用
那跟日期由大往小排(DESC)取第一個,不是一樣的意思?

.ToList() 是把所有的SQL查詢結果都傳回本地做成collection,再取Last,First..資料少沒什麼差別,資料多.........天知道會發生什麼事?
還是建議用LINQ的TAKE(n)在SQL端就處理好(跟SELECT TOP n等效)

int Revision = 
    db.PaperFiles
    .Where(p => p.PaperId == PaperId && 
        p.MemberId == MemberId && 
        p.SubmittedType == submittedType 
        && p.Stage == 2)
    .OrderByDescding(od=>od.UploadDate)
    .Take(1).Revision;

會以 SELECT TOP 1 * FROM PaperFiles WHERE ...... ORDER BY UploadDate DESC 執行

那如果是之前討論的寫法

int Revision = db.PaperFiles.Where(......).OrderBy(d => d.UploadDate).ToList().LastOnDefault();

則是 SELECT * FROM .... ORDER BY ..... ,有幾筆傳幾筆,只有三筆就傳三筆,有30萬筆也會照樣造句....你不在意網路流量跟本地記憶體被GC丟棄的資料量嗎?

leo226 iT邦新手 4 級 ‧ 2019-08-14 10:29:36 檢舉

了解,又上了一課,感謝japhenchen大師指導

我要發表回答

立即登入回答