2015-03-25 48 views
4

我已經寫了一堆通用的C#幫助函數作爲我的SQL查詢的基礎。所有的null對象參數都被轉換爲DBNull.Value。但是當目標列是varbinary時,它告訴我string類型與binary不兼容,我必須轉換。爲什麼DBNull.Value需要適當的SqlDbType?

爲什麼我需要在C#中使用SqlDbType a DBNull.Value是否有任何通用的方法來解決這個問題?

// works for nvarchar but throws for varbinary columns 
// notice the lack of SqlDbType as I don't know it for a null object 
var param1 = new SqlParameter(); 
param1.Name = "@Param1"; 
param1.Value = DBNull.Value; 

這是一個空......它不需要任何類型。 SQL服務器知道null的類型。在SQL中,你說[Column] IS NULL而不是[Column] IS TYPE NULL。所以null是無類型的。目標列從查詢中解析而不是SqlDbType

我剛剛發現這個非常不直觀的(明確鍵入空值)。我想知道如果我失去了一些東西......

代碼是這樣的:

SqlCommand CreateCommand(string query, params object[] arguments) { ... } 
// in here I walk the parameters and build the proper SqlParameter for them. 
// this saves me from setting up the SqlParameters by hand. 

PS字符串=的NVarChar和二進制表示VARBINARY。認真... PPS:對EF或任何類似的東西不感興趣。

+5

你的問題不太清楚。如何將字符串轉換爲與'DBNull.Value'相關的'binary'轉換?你能展示一些特定的代碼示例嗎? – 2015-03-25 11:45:25

+0

'string'在哪裏輸入圖片?如果它是'DBNull',它不是'string'。還有更多這個故事...... – DonBoitnott 2015-03-25 11:46:10

+3

另外,你可以顯示一些示例代碼,顯示你如何做到這一點?可能會提供一些有用的上下文 – 2015-03-25 11:47:24

回答

6

如果您未明確設定SqlParameterDBType - 它的默認值爲SqlDBType.NVarchar(請參閱MDSN以供參考)。

這就是爲什麼你會得到例外 - 你的參數類型是NVarchar,但目標列是VarBinary

請注意,您明確設置DBType只是因爲顯然ADO.NET不能從DBNull.Value推斷數據類型。

null不是一個類型 - 它只是由於缺少價值,所以如果我給你null你不能推斷的varchar如果它不存在或存在,例如,沒有int

UPDATE

我做了一些實驗。讓我們運行簡單的代碼:

SqlCommand cmd = new SqlCommand("select * from sometable where somecolumn = @Param1"); 
cmd.Connection = _MyConnection; 

var param = new SqlParameter(); 
param.ParameterName = "@Param1"; 
param.Value = DBNull.Value; 
cmd.Parameters.Add(param); 

cmd.Connection.Open(); 
try 
{ 
    cmd.ExecuteNonQuery(); 
} 
finally 
{ 
    cmd.Connection.Close(); 
} 

我們可以從SQL事件探查器看到的,這將被轉換爲實際的SQL查詢爲:所以在這裏我們一定會得到異常

exec sp_executesql 
    N'select * from sometable where somecolumn = @Param1', 
    N'@Param1 nvarchar(4000)', 
    @Param1=NULL 

如果somecolumn數據類型不能只是因爲@Param1數據類型明確設置爲varchar而被隱式轉換爲varchar

在第一眼看 - 這可能是足夠好的解釋,對吧?

但有一個問題讓我困惑。如果我們將執行不直查詢,但「虛擬」有varbinary作爲參數的存儲過程,讓我們說:

create procedure [dbo].[usp_Test] 
(
    @Param1 varbinary(max) 
) 
as 
begin 
    set nocount on 

    select null 
end 

現在,讓我們嘗試調用它像:

SqlCommand cmd = new SqlCommand("dbo.usp_Test"); 
cmd.CommandType = CommandType.StoredProcedure; 
... and so on (the rest of code dealing with parameter) 

現在,在SQL事件探查我們只會看到:

exec dbo.usp_Test @Param1=NULL 

這很奇怪,因爲它是絕對合法的調用,沒有明確的參數類型說明。實際上,如果我們在SQL Management Studio中調用這個函數 - 我們不會得到任何異常。

這部分ADO.NET行爲對我來說很奇怪。可能SQL Profiler不顯示完整的過程(儘管事實上我打開所有事件跟蹤),但我不知道。

無論如何 - 建議仍然是一樣的 - 總是明確指定SqlParameterDBType

+0

在SQL中,'datatype'是非常不相關的。這一切都取決於目標列。該類型存儲在表格定義中,而不是發送給我的內容。這不是SQLite,任何列都可以有任何類型。 – CodeAngry 2015-03-25 12:05:29

+0

但這不是關於SQL中發生了什麼。這與.NET中發生的事情很相似,除了底層的DBMS之外。 – 2015-03-25 12:08:43

+0

@ roryap仍然'DBNull.Value'是一個特殊的值。應該清楚它是一個null,不需要任何類型,因爲它是基於目標列來解析的。這就是我發現的愚蠢。爲什麼要輸入缺少的東西?我希望我錯過了一些東西,這不是設計。 – CodeAngry 2015-03-25 12:10:44