使用 ("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 ConnectionOpenDispose 的任何其他连接一样对待。听起来你在想 SqlConnection,当使用 "Context Connection = true;" 的连接字符串时,只需要打开一次,然后在完全完成之前不处理,而你会 Open / Dispose 否则它的几次。我看不出有任何理由在这两种情况下有不同的行为。


除此之外,如何最好地处理检测环境变化(在控制台应用程序和 SQLCLR 对象之间)?您有两个选择,两者都可能比您预期的更容易:

  1. 更改应用程序代码,但依赖于额外的配置文件:

    您可以在 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 可能会接受,可能不喜欢但可以容忍,或者可能会询问您的经理为你写信 ;-).

  2. 对应用程序代码进行非常微小的更改,但不要依赖额外的配置文件:

    您可以轻松地自动检测您当前是否在 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 属性.

  3. 链接的 MSDN 页面的 "Remarks" 部分中有所说明