问题
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:
Make no changes to the app code, but rely on an additional config file:
You can create a file named
sqlservr.exe.Config
in theC:\Program Files\Microsoft SQL Server\MSSQL{SqlVersion}.{SqlServerInstanceName}\MSSQL\Binn
folder (e.g.C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\Binn
, where the11
inMSSQL11
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 ;-).
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