Best way to handle connection when calling a function from a Console App or SQLCLR object with (“Context Connection=true”)

邮差的信 提交于 2020-01-02 18:36:03

问题


I have the following type of code in my data layer, which can be called from a console app, windows app, etc, with the proper connection string being read from the corresponding caller's App.Config file:

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();
   }    
}

I now want to call this same code from a SQLCLR stored procedure (within the database where these tables exist), where you would typically use a context connection:

using(SqlConnection connection = new SqlConnection("context connection=true")) 
{
    connection.Open();
    // etc etc etc
}

The most obvious approach that comes to mind is to overload the function:

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();
}

So apps with an App.Config could call the connection-less version and SQLCLR could call the version requiring a SqlConnection.

This "seems ok", but having to write the exact same style of overload for every single similar function makes it feel wrong.


回答1:


Taking the question (and comments on it) at face-value, why do you need:

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

? You should treat the Context Connection the same as any other connection with regards to Open and Dispose. It sounds like you are thinking that the SqlConnection, when using a Connection String of "Context Connection = true;", needs to be opened only once and then not disposed until completely done, whereas you would Open / Dispose of it several times otherwise. I don't see any reason to have differing behavior in these two scenarios.


All of that aside, how to best handle detecting the change in environment (between Console App and SQLCLR object)? You have two choices, both being probably easier than you are expecting:

  1. Make no changes to the app code, but rely on an additional config file:

    You can create a file named sqlservr.exe.Config in the C:\Program Files\Microsoft SQL Server\MSSQL{SqlVersion}.{SqlServerInstanceName}\MSSQL\Binn folder (e.g. C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\Binn, where the 11 in MSSQL11 is for SQL Server 2012). The format of this file, as should probably be expected, is as follows:

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

    This might be considered "cleaner" code, but does introduce an external dependency that your DBA might be ok with, might dislike but tolerate, or might ask your manager to write you up for ;-).

  2. Make a very minor change to the app code, but don't rely on an additional config file:

    You can easily auto-detect whether or not you are currently running in SQL Servers's CLR host by using the IsAvailable property of the SqlContext class. Just update your original code as follows:

    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;
    }
    

    This usage, by the way, is noted in the "Remarks" section of that linked MSDN page for the IsAvailable property.



来源:https://stackoverflow.com/questions/31260279/best-way-to-handle-connection-when-calling-a-function-from-a-console-app-or-sqlc

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!