iT邦幫忙

1

EF Linq Max(int) 出現轉型為 'System.Int32' 型別失敗

mvc

問題:
若資料表裡不存在任何一筆資料,則程式執行錯誤,若資料表裡有資料,則程式執行成功

PaperAuthor pa = new PaperAuthor();
int AuthorId = db.PaperAuthors.Select(p => p.AuthorId).Max() + 1;
pa.AuthorId = AuthorId;

錯誤訊息如下

轉型為 'System.Int32' 型別失敗,因為具體化的值為 Null。此結果型別的泛型參數或此查詢,兩者中必須有一個使用可為 Null 的型別。
描述: 在執行目前 Web 要求的過程中發生未處理的例外狀況。請檢閱堆疊追蹤以取得錯誤的詳細資訊,以及在程式碼中產生的位置。 

例外狀況詳細資訊: System.InvalidOperationException: 轉型為 'System.Int32' 型別失敗,因為具體化的值為 Null。此結果型別的泛型參數或此查詢,兩者中必須有一個使用可為 Null 的型別。

原始程式錯誤: 


行 93:                     {
行 94:                         PaperAuthor pa = new PaperAuthor();
行 95:                         int AuthorId = db.PaperAuthors.Select(p => p.AuthorId).Max() + 1;
行 96:                         pa.PaperId = PaperId;
行 97:                         pa.AuthorId = AuthorId;

知道是資料型別為Null造成的錯誤,可是試了幾個判斷Null方法再賦值的方式都失敗,想請教各位大師應該如何修正賦值比較OK呢?
感謝各位大師解惑了~謝謝

1
暐翰
iT邦大師 1 級 ‧ 2019-06-21 23:44:42
最佳解答

我的AuthorId是主鍵其中之一,所以是非null型態,因為當資料表是會新的狀況,或下WHERE條件下搜尋不到資料,那出來的的資料型別就為null,所以Convert.ToInt32就會錯誤。

找不資料情況下AuthorId為1版本:

var AuthorId = db.PaperAuthors
    .Where(x => x.PaperId == PaperId)
    .Select(p => p.AuthorId)
    .DefaultIfEmpty(0)
    .Max(id => (id + 1)) ;

上面邏輯相當於以下

var sql = "select isnull(max(AuthorId),0) + 1 from PaperAuthors where PaperId = @p0 ";
var AuthorId = db.Database.SqlQuery<int>(sql,PaperId);

另外看起來你想要模擬做出自增ID,建議不要這樣做,請使用資料庫本身的自增index

看更多先前的回應...收起先前的回應...
leo226 iT邦新手 5 級 ‧ 2019-06-22 12:00:46 檢舉

跟先進報告一下,我的AuthorId是主鍵其中之一,所以是非null型態,因為當資料表是會新的狀況,或下WHERE條件下搜尋不到資料,那出來的的資料型別就為null,所以Convert.ToInt32就會錯誤。

錯誤訊息如下

'/' 應用程式中發生伺服器錯誤。
轉型為 'System.Int32' 型別失敗,因為具體化的值為 Null。此結果型別的泛型參數或此查詢,兩者中必須有一個使用可為 Null 的型別。
描述: 在執行目前 Web 要求的過程中發生未處理的例外狀況。請檢閱堆疊追蹤以取得錯誤的詳細資訊,以及在程式碼中產生的位置。 

例外狀況詳細資訊: System.InvalidOperationException: 轉型為 'System.Int32' 型別失敗,因為具體化的值為 Null。此結果型別的泛型參數或此查詢,兩者中必須有一個使用可為 Null 的型別。

原始程式錯誤: 


行 93:                     {
行 94:                         PaperAuthor pa = new PaperAuthor();
行 95:                         var maxAuthorId = Convert.ToInt32(db.PaperAuthors.Where(x => x.PaperId == PaperId).Select(p => p.AuthorId).Max());
行 96:                         //int AuthorId = db.PaperAuthors.Where(x => x.PaperId == PaperId).Select(p => p.AuthorId).Max() + 1;
行 97:                         int AuthorId = maxAuthorId + 1;

所以就是要如何判斷搜出來的值為null時,賦予AuthorId=1的寫法。
用以下的if判斷式也無法執行

if (maxAuthorId == null)
{
    AuthorId = 1;
}
運算式的結果一律會是'false',因為類型int的值絕對不會等於類型int?的null
暐翰 iT邦大師 1 級 ‧ 2019-06-22 15:36:58 檢舉

leo226 我更新回答在內文了

leo226 iT邦新手 5 級 ‧ 2019-06-24 14:01:29 檢舉

感謝前輩的指點,我確實是想要模擬做出自增ID的功能,因為覺得用DB本身的自增index編碼因資料刪刪減減,但編碼卻只能無限的往上遞增,所以才想做這個自增ID的功能,測試了一下前輩指點的方法,還是遇到了以下的錯誤,錯誤訊息如下:

'/' 應用程式中發生伺服器錯誤。
不支援具有型別 'System.Int32' 的輸入及型別 'System.Nullable`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]' 的檢查的 'TypeAs' 運算式。LINQ to Entities 查詢中僅支援實體類型和複雜類型。
描述: 在執行目前 Web 要求的過程中發生未處理的例外狀況。請檢閱堆疊追蹤以取得錯誤的詳細資訊,以及在程式碼中產生的位置。 

例外狀況詳細資訊: System.NotSupportedException: 不支援具有型別 'System.Int32' 的輸入及型別 'System.Nullable`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]' 的檢查的 'TypeAs' 運算式。LINQ to Entities 查詢中僅支援實體類型和複雜類型。

原始程式錯誤: 


行 93:                     {
行 94:                         PaperAuthor pa = new PaperAuthor();
行 95:                         var AuthorId = db.PaperAuthors.Where(x => x.PaperId == PaperId).Select(p => p.AuthorId).Max(id => (id + 1) as int?) ?? 1;
行 96: 
行 97:                         pa.PaperId = PaperId;
fillano iT邦超人 1 級 ‧ 2019-06-25 11:06:27 檢舉

你要自己實做自增長id,你就需要考慮多人同時競爭存取資源(race)的問題,至少要鎖表(lock table),並且考慮到萬一產生的id重複,那要怎樣處理。

linq語法是一種程式語言中的程式語言,他會在materialize時經過編譯成sql來執行,同時也不完全等同於C#,不是所有C#型別跟處理這些型別的方法都能拿進去用的(因為實際執行的是SQL)。你不要在這裡做計算或轉型,而是把結果賦值給var xxx之後,判斷xxx是否是null再來處理比較好。

暐翰 iT邦大師 1 級 ‧ 2019-06-25 13:12:02 檢舉

leo226
EF低版本不支持nullable<int>,可以改成使用DefaultIfEmpty(0)

var AuthorId = db.PaperAuthors
    .Where(x => x.PaperId == PaperId)
    .Select(p => p.AuthorId)
    .DefaultIfEmpty(0)
    .Max(id => (id + 1)) ;

或是使用SqlQuery(最直覺)
另外可以參考fillano大大的回應,這問題很重要
最後標題建議改成EF Linq Max(int) 出現轉型為 'System.Int32' 型別失敗

leo226 iT邦新手 5 級 ‧ 2019-06-26 14:25:27 檢舉

感謝各位先進指點,測試用暐翰前輩的方法,可順利執行。
雖然一開始想要做自增長id功能,但其實也沒有一定要這麼做,可以用DB本身的自增長Id功能替代。
只是想說都遇到問題了,也上來提問了,如果可以解決問題並上到一課,那是最好不過的了,所以感謝各位大大提供的建議,獲益良多,謝謝。

1
PotRookie
iT邦新手 5 級 ‧ 2019-06-21 20:55:24
小魚 iT邦高手 1 級 ‧ 2019-06-21 23:36:00 檢舉

同意

leo226 iT邦新手 5 級 ‧ 2019-06-22 12:15:35 檢舉

跟先進報告一下,試著用Int32.TryParse來解決

PaperAuthor pa = new PaperAuthor();
var maxAuthorId = db.PaperAuthors.Where(x => x.PaperId == PaperId).Select(p => p.AuthorId).Max().ToString();
int AuthorId;
bool success = Int32.TryParse(maxAuthorId, out AuthorId);
if (!success)
{
    AuthorId = 1;
}
else
{
    AuthorId = Convert.ToInt32(maxAuthorId) + 1;
}

但在db.PaperAuthors.Where(x => x.PaperId == PaperId).Select(p => p.AuthorId).Max().ToString();
這一段就錯,錯誤訊息如下。

'/' 應用程式中發生伺服器錯誤。
轉型為 'System.Int32' 型別失敗,因為具體化的值為 Null。此結果型別的泛型參數或此查詢,兩者中必須有一個使用可為 Null 的型別。
描述: 在執行目前 Web 要求的過程中發生未處理的例外狀況。請檢閱堆疊追蹤以取得錯誤的詳細資訊,以及在程式碼中產生的位置。 

例外狀況詳細資訊: System.InvalidOperationException: 轉型為 'System.Int32' 型別失敗,因為具體化的值為 Null。此結果型別的泛型參數或此查詢,兩者中必須有一個使用可為 Null 的型別。

原始程式錯誤: 


行 93:                     {
行 94:                         PaperAuthor pa = new PaperAuthor();
行 95:                         var maxAuthorId = db.PaperAuthors.Where(x => x.PaperId == PaperId).Select(p => p.AuthorId).Max().ToString();
行 96:                         int AuthorId;
行 97:                         bool success = Int32.TryParse(maxAuthorId, out AuthorId);
0
舜~
iT邦新手 1 級 ‧ 2019-06-23 16:53:11

兩邊都用 (int?) 來強制轉型呢?

我要發表回答

立即登入回答