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

Dan*_*ann 15 c# sql-server sql-variant table-valued-parameters sql-server-2012

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

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

我在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();
Run Code Online (Sandbox Code Playgroud)

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

不支持"值"列的类型.类型是'对象'

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

irc*_*lie 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;
Run Code Online (Sandbox Code Playgroud)


bri*_*ian -1

希望您能够很好地利用这个“一刀切”的数据模型。通常,当您尝试扩展时,由于对基于集合的关系代数和可管理性的误解,它会在您面前爆炸。也许您已经考虑过这一点。我不想开发关于这个模型的 ETL 或报告。

请记住,您正在尝试将对象插入到数据库引擎中,而它不了解底层结构。该对象是如此通用,以至于对象的接收者不知道如何解释它。该对象具有属性,但只有在有明确指令或使用反射来识别基础类型以解包它们时,您才能够访问这些属性。(据我所知)在不知道任何相关信息的情况下可靠地将对象转换为基础类型的唯一方法是通过使用反射。也许一些 .Net 专家会以其他方式告诉我。

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

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