c# - 从控制台应用程序或 SQLCLR 对象使用 ("Context Connection=true"调用函数时处理连接的最佳方法)

标签 c# sql-server sqlclr

我的数据层中有以下类型的代码,可以从控制台应用程序、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 的版本。

这“看起来没问题”,但是必须为每个相似的函数编写完全相同的重载风格,这让人感觉不对。

最佳答案

从表面上看这个问题(及其评论),你为什么需要:

the option of passing in an existing connection when calling from a SQLCLR procedure

?在OpenDispose 方面,您应该将Context Connection 与任何其他连接一样对待。听起来您认为 SqlConnection 在使用 "Context Connection = true;" 连接字符串时只需要打开一次,然后直到完全释放为止完成,否则您将Open/Dispose多次。我认为没有任何理由在这两种情况下有不同的行为。


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

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

    您可以在C:\Program Files\Microsoft SQL Server\MSSQL{SqlVersion}.{SqlServerInstanceName}\MSSQL\Binn中创建名为sqlservr.exe.Config的文件code> 文件夹(例如 C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\Binn,其中 MSSQL11 中的 11 是对于 SQL Server 2012)。正如预期的那样,该文件的格式如下:

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
        <connectionStrings>
            <add name="CoolioAppDB" connectionString="Context Connection = true;" />
        </connectionStrings>
    </configuration>
    

    这个可能被认为是“更干净”的代码,但是确实引入了外部依赖,您的 DBA 可能会接受,可能不喜欢但容忍,或者可能会要求您的经理给您写信;- )。

  2. 对应用代码进行非常微小更改,但不要依赖其他配置文件:

    您可以使用 IsAvailable 轻松自动检测当前是否在 SQL Server 的 CLR 主机中运行。 SqlContext 类的属性。只需按如下方式更新您的原始代码:

    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 页面的“备注”部分中进行了说明。

关于c# - 从控制台应用程序或 SQLCLR 对象使用 ("Context Connection=true"调用函数时处理连接的最佳方法),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31260279/

相关文章:

sql - 如何在存储过程中调用C#函数

c# - 获取文件的相对路径?

c# - 如何在 C# Windows 窗体应用程序中将焦点发送到 tabindex 低于当前控件的控件?

c# - Polly 如何能够重新发送相同的 HTTP 请求?

sql-server - DISTINCT 是否总是隐含在 IN 子句中使用的子查询中?

c# - SQL Server 在哪里存储已部署的 CLR 程序集?

c# - 如何在网络上制作程序 "discoverable"?

sql - 在 SQL Server 中按 COUNT 子查询进行分组

sql-server - 乘以最大行并附加到列表

sql - 计算字符串中嵌入的总文件名和唯一文件名