在sql_variant列的表值参数中传递’object’类型的参数

我在SQL Server 2012中有一个表值参数定义为:

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(); 

然后,我在ExecuteNonQuery调用上从SQL Server收到以下错误:

不支持“值”列的类型。 类型是’对象’

我发现有人在3年前遇到了同样的问题,当时它被认定为已知的微软漏洞。 但是,该错误的链接已被破坏。 有谁知道是否有关于错误状态或潜在解决方法的最新信息? 就目前而言,这个bug确实会sql_variant字段的价值。

这篇文章现在已经很多年了,但我遇到了同样的问题,并找到了解决方案。 如果不使用DataTable,而是填充SqlDataRecord的集合,则可以将SqlDataRecord的数据类型设置为SqlDbType.Variant。

  List dataTable = new List(); var dr = new SqlDataRecord( new SqlMetaData("Id", SqlDbType.Int), new SqlMetaData("Value", SqlDbType.Variant)); dr.SetInt32(0, id); dr.SetValue(1, myObject); dataTable.Add(dr); [...] SqlCommand sqlCommand = new SqlCommand("dbo.MyProc"); var structuredParam = sqlCommand.Parameters.Add("myTableParam", SqlDbType.Structured); structuredParam.Value = dataTable; 

希望您能够很好地使用这种“一刀切”的数据模型。 通常情况下,当您尝试缩放时,由于对基于集合的关系代数和可攻击性的误解,它会在您的脸上爆炸。 也许你已经考虑过这个了。 我不想开发关于这个模型的ETL或报告。

请记住,您正在尝试将对象插入到数据库引擎中,而该对象不了解底层结构。 该对象是如此通用,以至于对象的接收者不知道如何解释它。 该对象具有属性,但是如果您有明确的指令,或者您使用reflection来标识要解包它们的基础类型,那么您将只能访问这些属性。 我知道的唯一方法是将对象可靠地转换为基础类型,而不需要了解它,通过使用reflection。 也许一些.Net专家会以其他方式填补我。

通用对象类型不能存储为像这样的sql_variant。 甚至sql_variant也需要一些强类型的值。 SQL Server不会隐式使用reflection来尝试找出数据类型(以及底层数据的值)是什么。

您可以使用System.Reflection的GetType方法,然后在插入之前抛出case语句以进行相应的转换。

不幸的是,我现在没时间完全回答这个问题,但我可以帮助你走上正确的道路。

我过去所做的不是使用TVP,而是使用XML参数,将数据集(或任何POCO)序列化为XML,将该XML传递给proc,然后使用“.nodes”属性xml变量的(和其他成员)提取临时表,本地表变量,“工作表”等所需的内容…

这很模糊,但是如果你序列化那个数据集,并检查创建的xml,并阅读在线书籍中的XML数据类型,你可能会弄清楚如何完成你的任务。

如果这没有帮助,我将在明天尝试整理一个实际的解决方案,因为我刚刚离开这个问题,因为我要离开这一天。

干杯!!