【问题标题】:Passing parameter of type 'object' in table-valued parameter for sql_variant column在 sql_variant 列的表值参数中传递“对象”类型的参数
【发布时间】:2012-12-18 08:52:23
【问题描述】:

我在 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 收到以下错误:

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

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

【问题讨论】:

  • @JonSeigel 我已经添加了 C# 调用代码。
  • 您选择sql_variant的原因是什么?只是好奇。
  • @codingbiz 该字段需要存储字符串、日期和数值。我可以在代码中进行手动转换,但这就是 sql_variant 应该为我做的。
  • @Dan 你最后是怎么处理这个问题的?
  • 目前提到的MS Connect link似乎还可以;该错误未修复。

标签: c# sql-server sql-server-2012 table-valued-parameters sql-variant


【解决方案1】:

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

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

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

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

【讨论】:

  • 此 TVP 和 proc 位于我的数据模型的外围,不在性能关键或搜索密集型区域。在这种特殊情况下,我希望 SQL Server 为我管理类型转换,而不是自己滚动。
【解决方案2】:

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

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

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

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

干杯!!

【讨论】:

    【解决方案3】:

    这篇文章已经有很多年了,但我遇到了同样的问题并找到了解决方案。如果您不使用 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;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-07-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-24
      相关资源
      最近更新 更多