【发布时间】:2017-01-15 10:32:22
【问题描述】:
我在 SQL Server 2012 中编写了一个 SQL Server CLR 用户定义类型 (UDT)。我已经能够通过 SQL 测试脚本访问它,并将它用作局部变量,在表中定义它,并且通过 Visual Studio 和 SQL Server Management Studio 对其进行了测试。
我们有一个服务,它以一种相当通用的方式使用 SQLBulkCopy 来拾取放置在目录中的文件,然后将它们的内容插入到适当的表中。当我将我的 UDT 作为其中一个表中的列添加时,我收到来自 WriteToServer( DataTable ) 调用的错误。
UDT 列作为 System.String 传递,希望在 SQL Server 中调用 UDT 的 Parse() 方法以将其转换为内部类型。我还尝试在此客户端程序中声明 UDT 类,并将数据直接作为 UDT 类型传递。
在任何一种情况下,我都会收到此错误消息(经过编辑以删除我的专有名称)
在程序集“MyType”中找不到类型“MyNamespace.MyType”的方法“Read”
我已经查看了尽可能多的关于此错误消息的类似问题,它们通常指的是 CREATE 语句的格式。此外,它们通常指的是 CLR 函数,而不是 CLR 类型,它们略有不同。这是我的:
创建类型 [dbo].[MyType]
外部名称 [MyType].[MyNamespace.MyType]
我怀疑这可能不是问题,而是与 SQLBulkCopy 如何与 SQLCLR UDT 交互有关。对于这种特殊的组合,很难找到任何深入的解释。
编辑 #1 - 这是自定义序列化。
[Serializable]
[Microsoft.SqlServer.Server.SqlUserDefinedType( Format.UserDefined, MaxByteSize = -1 )]
public struct MyType: INullable, IBinarySerialize
编辑 #2 - 授予执行权限
GRANT EXECUTE
ON TYPE :: MyType
TO PUBLIC
编辑 #3 - 调整测试代码
CREATE TABLE [dbo].[TestMyType]
(
[SourceMachine] [varchar](32) NULL,
[Output] MyType NULL
)
更新者
try
{
DataTable dataTable = new DataTable( "[TestMyType]" );
dataTable.Columns.Add( "SourceMachine", typeof( System.String ) );
dataTable.Columns.Add( "Output", typeof( MyNamespace.MyType ) );
dataTable.Rows.Add( "Ron1", MyNamespace.MyType.Parse( "This is string 1" ) );
dataTable.Rows.Add( "Ron2", MyNamespace.MyType.Parse( "This is string 2" ) );
dataTable.Rows.Add( "Ron3", MyNamespace.MyType.Parse( "This is string 3" ) );
SqlBulkCopy sqlBulkCopy = new SqlBulkCopy( conn );
sqlBulkCopy.DestinationTableName = "[TestMyType]";
sqlBulkCopy.WriteToServer( dataTable );
}
catch ( Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
throw;
}
这给出了与上面显示的相同的错误消息。
编辑 #4 - 从问题中消除 SqlBulkCopy
我使用参数化的 INSERT 重新创建了该问题。我将它设置为将 UDT 对象从客户端传递到服务器作为直接使用 UDT 实例的参数。
string sInsert = "INSERT INTO TestMyType VALUES (?, ?)";
SqlCommand command = new SqlCommand(sInsert, conn);
SqlParameter parm1 = new SqlParameter("SourceMachine", "This is Machine 01");
SqlParameter parm2 = new SqlParameter("Output", MyNamespace.MyType.Parse( "This is INSERT 01" ) );
parm2.UdtTypeName = "MyType";
command.Parameters.Add(parm1);
command.Parameters.Add(parm2);
int nResult = command.ExecuteNonQuery();
给予
A first chance exception of type 'System.Data.SqlClient.SqlException'
occurred in System.Data.dll
Additional information: Could not find method 'Read' for
type 'MyNamespace.MyType' in assembly 'MyType'
【问题讨论】:
-
您的 UDT 是使用原生序列化还是自定义序列化?
-
是自定义序列化。 [Serializable] [Microsoft.SqlServer.Server.SqlUserDefinedType(Format.UserDefined, MaxByteSize = -1)] public struct MyType: INullable, IBinarySerialize
-
抱歉,我不知道如何使它看起来像注释中的代码块。我已经尝试了所有可以在帮助页面中找到的方法。
-
没问题;-)。在 cmets 中,只允许降价的一个子集。您可以对代码使用反引号。看这里:Markdown Help。您可以通过单击编辑器右上角的 ? 进入该帮助页面,然后单击“高级帮助”。今晚或明天晚些时候我会看看这个。此外,如果您使用某人的
@姓名以便他们得到通知,这也会有所帮助。通知总是发送到评论所在的问题或答案的发布者。 -
当您说您尝试“在此客户端程序中声明UDT类,并直接将数据作为UDT类型传递”时,您的意思是您设置了列输入
DataTable作为您的类型,然后加载数据?不确定是否需要直接调用Parse方法。但是看看这个answer。此外,要通过 BCP / SqlBulkCopy 直接发送数据,它需要采用二进制格式,如 source code。我现在正在测试。
标签: sql-server sql-server-2012 sqlclr sqlbulkcopy user-defined-types