16

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

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

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

我发现有人在 3 年前被确定为已知的 Microsoft 错误时遇到了同样的问题。但是,该错误的链接已损坏。有谁知道是否有关于错误状态或潜在解决方法的更新信息?就目前而言,这个错误确实扼杀了sql_variant字段的价值。

4

3 回答 3

5

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

 List<SqlDataRecord> dataTable = new List<SqlDataRecord>();
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;
于 2018-10-10T09:08:53.657 回答
1

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

请记住,您正在尝试将对象插入到数据库引擎中,而该对象不了解底层结构。对象是如此通用,以至于对象的接收者不知道如何解释它。该对象具有属性,但只有当您有明确的说明或使用反射来识别底层类型以解包它们时,您才能访问这些属性。将对象可靠地转换为底层类型的唯一方法(我知道)是通过使用反射而不知道它的任何内容。也许一些 .Net 大师会以其他方式填补我的空白。

通用对象类型不能像这样存储为 sql_variant。甚至 sql_variant 也需要某种强类型的值。SQL Server 不会隐式使用反射来尝试找出数据类型(然后是基础数据的值)是什么。

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

于 2013-01-04T06:38:47.153 回答
0

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

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

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

如果这没有帮助,我明天会尝试制定一个实际的解决方案,因为我在离开这一天时刚刚遇到了这个问题。

干杯!!

于 2015-03-06T01:28:00.263 回答