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数据类型时,您可能会弄清楚如何完成您的任务。

如果这样做没有帮助,那么明天我会试着组合一个实际的解决方案,就像我刚刚离开那天时遇到的那个问题。

干杯!