使用 ("Context Connection=true") 从控制台应用程序或 SQLCLR 对象调用函数时处理连接的最佳方式
Best way to handle connection when calling a function from a Console App or SQLCLR object with ("Context Connection=true")
我的数据层中有以下类型的代码,可以从控制台应用程序、windows 应用程序等调用,并从相应调用者的 App.Config 文件:
public static udsDataset GetDataset(int datasetID)
{
string connectionString =
ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
string sql = @"select * from Dataset WHERE DatasetID=@datasetID";
using (SqlConnection conn = new SqlConnection(connectionString))
{
// Dapper query:
return conn.Query<udsDataset>(sql, new {datasetID } ).First();
}
}
我现在想从 SQLCLR 存储过程(在存在这些表的数据库中)调用相同的代码,您通常会在其中使用 context connection:
using(SqlConnection connection = new SqlConnection("context connection=true"))
{
connection.Open();
// etc etc etc
}
想到的最明显的方法是重载函数:
public static udsDataset GetDataset(int datasetID)
{
string connectionString =
ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
using (SqlConnection conn = new SqlConnection(connectionString))
{
return GetDataset(datasetID, conn);
}
}
public static udsDataset GetDataset(int datasetID, SqlConnection conn)
{
// caller is responsible for closing and disposing connection
string sql = @"select * from Dataset WHERE DatasetID=@datasetID";
return conn.Query<udsDataset>(sql, new {datasetID } ).First();
}
因此具有 App.Config 的应用程序可以调用无连接版本,而 SQLCLR 可以调用需要 SqlConnection 的版本。
这 "seems ok",但是必须为每个类似的函数编写完全相同的重载样式让人感觉不对。
从表面上看问题(及其评论),你为什么需要:
the option of passing in an existing connection when calling from a SQLCLR procedure
?您应该将 Context Connection
与 Open
和 Dispose
的任何其他连接一样对待。听起来你在想 SqlConnection
,当使用 "Context Connection = true;"
的连接字符串时,只需要打开一次,然后在完全完成之前不处理,而你会 Open
/ Dispose
否则它的几次。我看不出有任何理由在这两种情况下有不同的行为。
除此之外,如何最好地处理检测环境变化(在控制台应用程序和 SQLCLR 对象之间)?您有两个选择,两者都可能比您预期的更容易:
不更改应用程序代码,但依赖于额外的配置文件:
您可以在 C:\Program Files\Microsoft SQL Server\MSSQL{SqlVersion}.{SqlServerInstanceName}\MSSQL\Binn
文件夹中创建一个名为 sqlservr.exe.Config
的文件(例如 C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\Binn
,其中 MSSQL11
中的 11
用于 SQL 服务器 2012)。正如预期的那样,该文件的格式如下:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<connectionStrings>
<add name="CoolioAppDB" connectionString="Context Connection = true;" />
</connectionStrings>
</configuration>
可能 被视为 "cleaner" 代码,但确实引入了外部依赖关系,您的 DBA 可能会接受,可能不喜欢但可以容忍,或者可能会询问您的经理为你写信 ;-).
对应用程序代码进行非常微小的更改,但不要依赖额外的配置文件:
您可以轻松地自动检测您当前是否在 SQL 服务器的 CLR 主机中 运行,方法是使用 SqlContext
class。只需按如下方式更新您的原始代码:
string connectionString = "Context Connection = true;"; // default = SQLCLR connection
if (!SqlContext.IsAvailable) // if not running within SQL Server, get from config file
{
connectionString =
ConfigurationManager.ConnectionStrings["CoolioAppDB"].ConnectionString;
}
顺便说一下,这种用法在 IsAvailable
属性.
链接的 MSDN 页面的 "Remarks" 部分中有所说明
我的数据层中有以下类型的代码,可以从控制台应用程序、windows 应用程序等调用,并从相应调用者的 App.Config 文件:
public static udsDataset GetDataset(int datasetID)
{
string connectionString =
ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
string sql = @"select * from Dataset WHERE DatasetID=@datasetID";
using (SqlConnection conn = new SqlConnection(connectionString))
{
// Dapper query:
return conn.Query<udsDataset>(sql, new {datasetID } ).First();
}
}
我现在想从 SQLCLR 存储过程(在存在这些表的数据库中)调用相同的代码,您通常会在其中使用 context connection:
using(SqlConnection connection = new SqlConnection("context connection=true"))
{
connection.Open();
// etc etc etc
}
想到的最明显的方法是重载函数:
public static udsDataset GetDataset(int datasetID)
{
string connectionString =
ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
using (SqlConnection conn = new SqlConnection(connectionString))
{
return GetDataset(datasetID, conn);
}
}
public static udsDataset GetDataset(int datasetID, SqlConnection conn)
{
// caller is responsible for closing and disposing connection
string sql = @"select * from Dataset WHERE DatasetID=@datasetID";
return conn.Query<udsDataset>(sql, new {datasetID } ).First();
}
因此具有 App.Config 的应用程序可以调用无连接版本,而 SQLCLR 可以调用需要 SqlConnection 的版本。
这 "seems ok",但是必须为每个类似的函数编写完全相同的重载样式让人感觉不对。
从表面上看问题(及其评论),你为什么需要:
the option of passing in an existing connection when calling from a SQLCLR procedure
?您应该将 Context Connection
与 Open
和 Dispose
的任何其他连接一样对待。听起来你在想 SqlConnection
,当使用 "Context Connection = true;"
的连接字符串时,只需要打开一次,然后在完全完成之前不处理,而你会 Open
/ Dispose
否则它的几次。我看不出有任何理由在这两种情况下有不同的行为。
除此之外,如何最好地处理检测环境变化(在控制台应用程序和 SQLCLR 对象之间)?您有两个选择,两者都可能比您预期的更容易:
不更改应用程序代码,但依赖于额外的配置文件:
您可以在
C:\Program Files\Microsoft SQL Server\MSSQL{SqlVersion}.{SqlServerInstanceName}\MSSQL\Binn
文件夹中创建一个名为sqlservr.exe.Config
的文件(例如C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\Binn
,其中MSSQL11
中的11
用于 SQL 服务器 2012)。正如预期的那样,该文件的格式如下:<?xml version="1.0" encoding="utf-8" ?> <configuration> <connectionStrings> <add name="CoolioAppDB" connectionString="Context Connection = true;" /> </connectionStrings> </configuration>
可能 被视为 "cleaner" 代码,但确实引入了外部依赖关系,您的 DBA 可能会接受,可能不喜欢但可以容忍,或者可能会询问您的经理为你写信 ;-).
对应用程序代码进行非常微小的更改,但不要依赖额外的配置文件:
您可以轻松地自动检测您当前是否在 SQL 服务器的 CLR 主机中 运行,方法是使用
SqlContext
class。只需按如下方式更新您的原始代码:string connectionString = "Context Connection = true;"; // default = SQLCLR connection if (!SqlContext.IsAvailable) // if not running within SQL Server, get from config file { connectionString = ConfigurationManager.ConnectionStrings["CoolioAppDB"].ConnectionString; }
顺便说一下,这种用法在
IsAvailable
属性. 链接的 MSDN 页面的 "Remarks" 部分中有所说明