13

我在SQL Server 2012的一個表值參數定義爲:在表值參數傳遞類型「對象」的參數爲SQL_VARIANT柱

CREATE TYPE [dbo].[TVP] AS TABLE (
    [Id] [int] NOT NULL, 
    [FieldName] [nvarchar](100) NOT NULL, 
    [Value] [sql_variant] NOT NULL 
) 

我把它在C#與代碼看起來大致等以下內容:

var mdItems = new DataTable(); 
mdItems.Columns.Add("Id", typeof(int)); 
mdItems.Columns.Add("FieldName", typeof(string)); 
mdItems.Columns.Add("Value", typeof(object)); 
mdItems.Rows.Add(new object[] {2, "blah", "value"}); //'value' is usually a string 
SqlCommand sqlCommand = conn.CreateCommand(); 
sqlCommand.CommandText = "[WriteFieldValues]"; 
sqlCommand.CommandType = CommandType.StoredProcedure; 
sqlCommand.Parameters.AddWithValue("@FieldValues", mdItems); 
sqlCommand.ExecuteNonQuery(); 

然後我得到從SQL Server以下錯誤的ExecuteNonQuery電話:

不支持列'值'的類型。該類型是「對象」

我發現someone誰3年前遇到了同樣的問題,當它被確定爲一個已知的Microsoft錯誤。雖然,該錯誤的鏈接被打破。有誰知道是否有關於錯誤狀態或潛在解決方法的最新信息?就目前來看,這個bug確實會殺死sql_variant字段的值。

+0

@JonSeigel我已經添加了C#調用代碼。 – Dan

+0

你選擇'sql_variant'的原因是什麼?只是好奇。 – codingbiz

+0

@codingbiz該字段需要存儲字符串,日期和數字值。我可以在代碼中進行手動轉換,但這就是sql_variant應該爲我做的。 – Dan

回答

1

希望您對這種「一刀切」的數據模型有很好的使用。通常情況下,當你嘗試縮放時,由於對基於集合的關係代數和sargeability的誤解,它會在你的臉上炸開。也許你已經給了這個想法。我討厭開發ETL或者關於這個模型的報告。

請記住,您正試圖將一個對象插入到數據庫引擎中,它不知道底層結構。該對象如此通用以至於對象的接收者不知道如何解釋它。該對象具有屬性,但如果您有明確的指示,則只能訪問這些屬性,或者您使用反射來識別將其拆包的基礎類型。 唯一可以將對象可靠地轉換爲基礎類型(不知道任何關於它)的方法(我知道)是通過使用反射。也許一些.Net大師會以其他方式讓我滿足。

通用對象類型不能像這樣存儲爲sql_variant。即使sql_variant也需要強類型值。 SQL Server不會隱式地使用反射來試圖找出數據類型(以及底層數據的值)是什麼。

您可以使用System.Reflection的GetType方法,然後在插入前投入一個case語句進行相應的轉換。

+0

此TVP和proc位於我的數據模型的外圍,不在性能關鍵或搜索密集區域。在這種特殊情況下,我希望SQL Server爲我管理類型轉換,而不是滾動我自己的。 – Dan

0

不幸的是,我現在沒有時間來完全回答這個問題,但我可以幫助您找到正確的道路。

我過去所做的是,不是使用TVP,而是使用XML參數,將數據集(或任何POCO,作爲XML)序列化爲XML,將該XML傳遞到proc中,然後使用「 .nodes「屬性(和其他成員)的xml變量,以提取任何需要到臨時表,本地表變量,」工作表「等...

這是含糊的,但如果你序列化該數據集,並檢查在創建的xml中,並在Books On Line上閱讀XML數據類型時,您可能會弄清楚如何完成您的任務。

如果這樣做沒有幫助,那麼明天我會試着組合一個實際的解決方案,就像我剛剛離開那天時遇到的那個問題。

乾杯!