ADO.NET的SqlParameter(String,?Object)的構造函數第二個參數不能為0?

上述截圖的Line 22能正確執行,而Line 27卻拋異常(System.Data.SqlClient.SqlException). 查了一下MSDN (SqlParameter Constructor (String, Object) (System.Data.SqlClient)),裡面提到第二個參數需要把整數轉換成Object類型。

現在有兩個疑問,1:為什麼需要把Integer轉成Object類型?我查看了一下SqlParameter的所有重載構造函數, 第二個參數直接傳整數不會有衝突啊? 2:如果是有其它原因導致了第二個參數需要把整數轉換成Object類型, 那為什麼截圖裡的Line 22能正確執行呢?Line 22和Line 27兩種使用方式有區別嗎?

補充一下代碼文字版:

SqlConnection connection = new SqlConnection("sql connection string");
SqlCommand command = connection.CreateCommand();
command.CommandText = "select * from INFORMATION_SCHEMA.COLUMNS where ORDINAL_POSITION &> @para" ;
int value = 0;
command.Parameters.Add(new SqlParameter("para", value));
SqlDataAdapter adapter = new SqlDataAdapter(command);
DataTable table = new DataTable();
adapter.Fill(table);

adapter = new SqlDataAdapter(command);
command.Parameters.Clear();
command.Parameters.Add(new SqlParameter("para", 0)); //而這麼寫就可以了 command.Parameters.Add(new SqlParameter("para", (object)0))
adapter.Fill(table);

項目的版本是 .Net Framework 4.5.2, IDE是VS 2015.

Line 27的異常信息是:

The parameterized query "(@para bigint)select * from INFORMATION_SCHEMA.COLUMNS where ORD" expects the parameter "@para", which was not supplied.

@Ivony 提到說不要復用 SqlCommand 對象,我給分割成了兩個方法,還是會有同樣的錯誤,代碼源碼和運行截圖如下(更新後的截圖):


確定了,這是一個規範中定義的行為,先引用規範:

6.1.3 隱式枚舉轉換

隱式枚舉轉換允許將 decimal-integer-literal 0(或 0L 等)轉換為任何 enum-type 以及任何基礎類型為 enum-type 的 nullable-type。在後一種情況下,此轉換通過轉換為基礎 enum-type 並包裝結果(第 4.1.10 節)來計算。

也就是說,0這個特殊的數值字面量(不論其是什麼類型),有一個到任意枚舉類型的隱式類型轉換。

這個隱式類型轉換有兩個前提條件:

1、必須是0

2、必須是字面量。

你的例子正好符合這兩個條件,所以這個0d存在一個到SqlDbType這個枚舉的隱式類型轉換。因為其存在到SqlDbType和object兩個類型的隱式類型轉換,按照重載決策,SqlDbType是「更好的類型」,所以選擇SqlDbType的這個重載。

當你把這個0值放在一個變數傳進去的時候,則不符合上面的第二個前提條件,必須是字面量,所以此時不存在到SqlDbType的隱式類型轉換,所以這個時候選擇object的這個重載。


你把sql寫在程序里,那麼發生這種事情就不意外了。

正確的做法是,sql應該寫在資料庫存儲過程里,然後EF直接調用。


推薦閱讀:

處理XMLHttpRequest時如何判斷是否是自己網站發出的?
.net怎麼實現自己的非同步方法?
請各位前輩指導下簡練代碼的思路?
IoC/AOP 這些開發範式為什麼在 .NET 平台上沒有被廣泛採用?
C# 是使用引用計數來發現垃圾對象的嗎?

TAG:NET | C# | MicrosoftSQLServer |