2008-08-25 143 views
41

我經常遇到問題處理DataRowsSqlDataAdapters返回。當我嘗試填補對象使用這樣的代碼:什麼是最好的方式來處理DBNull的

DataRow row = ds.Tables[0].Rows[0]; 
string value = (string)row; 

什麼是這種類型的情況來處理DBNull's的最佳途徑。

+0

密切:[最高效的單向到檢查換的DBNull和 - 然後,分配到一個變量(http://stackoverflow.com/questions/221582/most-efficient-way -to-檢查換爲DBNull和-然後指派到一個變量) – nawfal 2013-12-11 16:42:38

回答

34

可以爲空的類型是好的,但只適用於不能以空格開頭的類型。

爲了一種「可空」問號追加到類型,例如:

int? value = 5; 

我也建議使用「as」關鍵字,而不是鑄造的。您只能在可爲空的類型上使用「as」關鍵字,因此請確保您正在投射已經爲空的東西(如字符串),或者使用上面提到的可空類型。這樣做的原因是

  1. 如果一個類型是空的,則「as」關鍵字返回null如果值是DBNull
  2. 它是ever-so-slightly faster than casting雖然only in certain cases。這本身並不是一個足夠好的理由來使用as,但加上它的原因是有用的。

我建議你做這樣的事情

DataRow row = ds.Tables[0].Rows[0]; 
string value = row as string; 

在上述情況下,如果row回來爲DBNull,然後value將成爲null,而不是拋出異常。請注意,如果您的數據庫查詢更改了返回的列/類型,使用as將導致您的代碼在默認情況下失敗並使值簡單null而不是在返回不正確的數據時拋出相應的異常,因此建議您進行測試以其他方式驗證您的查詢,以確保您的代碼庫發展時的數據完整性。

6

添加對System.Data.DataSetExtensions的引用,該引用添加了Linq對查詢數據表的支持。

這將是這樣的:

string value = (
    from row in ds.Tables[0].Rows 
    select row.Field<string>(0)).FirstOrDefault(); 
+2

+1:這個答案應該是更upvoted大概也接受了 - 絕對row.Field (「欄」)是最有效的,用於處理null(DBNull.Value)的可讀和乾淨的解決方案。還有用於將值寫入行的row.SetField (「column_name」,value)。 – 2012-12-19 23:20:45

2

我平時寫一個封裝內置Convert類我自己ConvertDBNull類。如果該值爲DBNull,則它將返回null(如果其引用類型)或默認值(如果其值類型)。 例子: - ConvertDBNull.ToInt64(object obj)回報Convert.ToInt64(obj)除非obj是爲DBNull在這種情況下,如果你不使用可空類型,它將返回0。

21

,做的最好的事情就是檢查是否該列的值是爲DBNull。如果它是DBNull,那麼設置你對相應的數據類型使用null/empty的引用。

DataRow row = ds.Tables[0].Rows[0]; 
string value; 

if (row["fooColumn"] == DBNull.Value) 
{ 
    value = string.Empty; 
} 
else 
{ 
    value = Convert.ToString(row["fooColumn"]); 
} 

隨着馬努說,你可以創建每個類型的重載轉換方法的轉換類,所以你不if/else語句塊必須辣椒代碼。

但是我會強調,如果你可以使用它們,可以爲空的類型是更好的路徑。理由是,對於非空類型,您將不得不求助於「幻數」來表示空值。例如,如果你將一個列映射到一個int變量,你將如何表示DBNull?通常你不能使用0,因爲在大多數程序中0有一個有效的含義。通常我會看到人們將DBNull映射到int.MinValue,但這可能也有問題。我最好的建議是這樣的:

  • 對於在數據庫中可以爲空的列,請使用可爲空的類型。
  • 對於數據庫中不能爲空的列,請使用常規類型。

可以使用可爲空的類型來解決這個問題。話雖如此,如果您使用的是舊版本的框架,或者爲不支持可空類型的人員工作,那麼代碼示例就可以解決這個問題。

+0

行if(行[「fooColumn」] == DBNull.Value)的作品,但不正確。它沒有被定義DBNull.Value應該被實現爲Singleton模式。更好的一行是:if(row [「fooColumn」]是DBNull) – doekman 2009-06-12 08:30:32

+0

@doekman - 實際上,DBNull *是一個單例類。引用MSDN:「DBNull是一個單例類,這意味着只有這個類的[DBNull.Value]實例可以存在。」 http://msdn.microsoft.com/en-us/library/system.dbnull.value.aspx – Greg 2009-12-22 16:39:42

+2

如果你想治療的DBNull爲空字符串行[「fooColumn」]。的ToString()將做到這一點。 – samir105 2012-12-23 08:27:46

1

出於某種原因,我已經受夠了做對DBNull.Value檢查的問題,所以我已經做過的事情有所差異,DataRow對象中的槓桿屬性:

if (row.IsNull["fooColumn"]) 
{ 
    value = string.Empty(); 
} 
{ 
else 
{ 
    value = row["fooColumn"].ToString; 
} 
5

如果你有控制即返回結果的查詢,你可以使用ISNULL()返回非空值是這樣的:

SELECT 
    ISNULL(name,'') AS name 
    ,ISNULL(age, 0) AS age 
FROM 
    names 

如果你的情況可以容忍這些魔法值代替NULL,採用這種方法可以解決這個問題通過你的整個應用程序,而不會混淆你的碼。

8

我總是發現使用If/Else檢查版本的清晰,簡潔和無問題,只能使用三元運算符。將所有內容保留在一行上,包括如果列爲空,則分配默認值。

因此,假設名爲「MyCol」一空Int32列,在這裏我們想返回-99如果列空,但返回整數值如果列不爲空:

return row["MyCol"] == DBNull.Value ? -99 : Convert.ToInt32(Row["MyCol"]); 

這是與上面的If/Else獲勝者相同的方法 - 但是我發現,如果您從數據讀取器中讀取多列,這是一個真正的獎勵,所有列讀線都排在一起,排列整齊,因爲它更容易現場錯誤:

Object.ID = DataReader["ID"] == DBNull.Value ? -99 : Convert.ToInt32(DataReader["ID"]); 
Object.Name = DataReader["Name"] == DBNull.Value ? "None" : Convert.ToString(DataReader["Name"]); 
Object.Price = DataReader["Price"] == DBNull.Value ? 0.0 : Convert.ToFloat(DataReader["Price"]); 
0

如果您擔心在預期時獲取DBNull g字符串,一種選擇是將DataTable中的所有DBNull值轉換爲空字符串。

這樣做很簡單,但會增加一些開銷,特別是在處理大型數據表時。選中此link,顯示如何做到這一點,如果你有興趣

+0

Someties知道空字符串和空字符串之間的區別很重要。例如,將值設置爲空字符串,而不是僅設置值。 – Mykroft 2008-10-24 17:44:12

1

布拉德·艾布拉姆斯發佈有關短短几天前 http://blogs.msdn.com/brada/archive/2009/02/09/framework-design-guidelines-system-dbnull.aspx

總結的東西「避免使用System.DBNull。身高可空來代替。「

這裏是我的兩分錢(未經測試的代碼:))

// Or if (row["fooColumn"] == DBNull.Value) 
if (row.IsNull["fooColumn"]) 
{ 
    // use a null for strings and a Nullable for value types 
    // if it is a value type and null is invalid throw a 
    // InvalidOperationException here with some descriptive text. 
    // or dont check for null at all and let the cast exception below bubble 
    value = null; 
} 
else 
{ 
    // do a direct cast here. dont use "as", "convert", "parse" or "tostring" 
    // as all of these will swallow the case where is the incorect type. 
    // (Unless it is a string in the DB and really do want to convert it) 
    value = (string)row["fooColumn"]; 
} 

而且一個問題......你沒有使用ORM的原因嗎?

3

的DBNull實現的ToString() 。像其他一切不需要做任何事情而不是硬投,調用該對象的的ToString()方法

DataRow row = ds.Tables[0].Rows[0]; 
string value; 

if (row["fooColumn"] == DBNull.Value) 
{ 
    value = string.Empty; 
} 
else 
{ 
    value = Convert.ToString(row["fooColumn"]); 
} 

這將成爲:

DataRow row = ds.Tables[0].Rows[0]; 
string value = row.ToString() 

DBNull.ToString()返回的String.Empty

我會想象這是你要找的

1

最好的做法你也應該看看擴展方法。 Here是處理這個scenerio的一些例子。

推薦read

3

值得一提的是,這DBNull.Value.ToString()等於String.Empty

你可以用你的優勢:

DataRow row = ds.Tables[0].Rows[0]; 
string value = row["name"].ToString(); 

然而,這僅適用於絃樂,其他一切我會使用linq方式或擴展方法。至於我自己,我寫了檢查的DBNull一點點擴展方法,並與數據表工作時,即使不通過Convert.ChangeType(...)

int value = row.GetValueOrDefault<int>("count"); 
int value = row.GetValueOrDefault<int>("count", 15); 
2

通常情況下,鑄造你必須處理這種情況下,如果行字段可以是零或DBNull的,通常我處理,像這樣:

string myValue = (myDataTable.Rows[i]["MyDbNullableField"] as string) ?? string.Empty; 

的「爲」經營者返回null無效轉換的,像DBNull的字符串,而「?」如果第一個爲空,則返回 表達式右側的項。

相關問題