我需要将一些代码从旧项目移动到新项目。旧项目使用DLL与存储过程(32位版本),但我需要在64位SQL Server上使用此DLL,因此我需要重写这些过程。
我正在使用SQL Server 2008的存储过程编写dll。在Management Studio中我加载程序集,然后使用以下命令创建过程:
CREATE PROCEDURE ...
AS EXTERNAL NAME
旧的DLL过程只是使用与远程SQL Server的新连接来在其上运行存储过程并返回结果。
因此,在我的程序中,我为远程服务器创建了一个SqlConnection
并在远程服务器上运行存储过程:
using (SqlConnection connection = new SqlConnection(String.Format("User ID={0};Password={1};Persist Security Info=True;Initial Catalog={2};Data Source={3}", Login, Password, DBName, ServerName)))
{
connection.Open();
SqlCommand command = new SqlCommand("Exec ProcName", connection);
SqlDataReader reader = command.ExecuteReader();
SqlContext.Pipe.Send(reader);
}
如果我在SSMS中运行此过程,它可以正常工作。但在旧项目中,它会引发错误:
Microsoft分布式事务处理协调器(MS DTC)已取消分布式事务。
MSDTC服务运行,我设置了所有安全参数。如何解决?也许还有其他方法来运行远程存储过程(链接服务器),但我需要保存旧的项目功能。
答案 0 :(得分:1)
有几件事情不太正确:
你为什么要重写任何东西?如果您有代码,最糟糕的情况就是重新编译新架构。
你为什么一开始做任何事情?代码应该针对“任何CPU”(在“项目属性”的“SQLCLR构建”选项卡中的“平台目标”下)编译,而不是专门针对32位或64位。如果它已经在“任何CPU”下编译,那么就无所事事了。在开始任何重新编译和/或重写之前,您是否在新系统上进行了测试?
不要使用String.Format
来创建连接字符串。相反,请使用SqlConnectionStringBuilder:
SqlConnectionStringBuilder _ConnectionStringBuilder =
new SqlConnectionStringBuilder();
_ConnectionStringBuilder.DataSource = ServerName;
_ConnectionStringBuilder.InitialCatalog = DBName;
_ConnectionStringBuilder.UserID = Login;
_ConnectionStringBuilder.Password = Password;
除非您绝对别无选择且必须使用此选项,否则请勿指定Persist Security Info=True;
使用:
创建new SqlCommand()
,而不是使用SqlCommand
using(SqlCommand command = connection.CreateCommand())
{
command.CommandText = "Exec ProcName";
}
请务必同时指定command.CommandType = CommandType.StoredProcedure;
,以便它执行实际的RPC调用而不是即席查询。这将要求您从“EXEC ProcName”的当前CommandText
中删除“EXEC”的文本;您只能指定[[DatabaseName.]SchemaName.]ProcName
。
SqlDataReader
是一次性对象,就像SqlConnection
和SqlCommand
一样,因此SqlDataReader reader = command.ExecuteReader()
应该包含在using()
构造中。
一旦上述项目得到纠正,您就可以通过简单地设置SqlConnectionStringBuilder的以下属性来修复错误:_ConnectionStringBuilder.Enlist = false
。
有关使用SQLCLR的更多详细信息和示例,请参阅我在SQL Server Central上就此主题撰写的系列文章:Stairway to SQLCLR(阅读该网站上的内容需要免费注册)。 / p>