想知道是否建议传递数据库连接对象(到其他模块)或让方法(在其他模块中)负责设置它。我倾向于让方法设置它,以便在使用之前不必检查连接的状态,只是让调用者将任何所需的数据传递给设置连接所需的调用方法。
答案 0 :(得分:13)
我个人喜欢使用严格的连接;打开它们,使用它们并关闭它们(在“使用”块中,所有都在本地方法中)。在大多数情况下,连接池将处理重新使用连接,因此这种方法没有实际开销。
传递连接使用的主要优点是可以传递事务;但是,TransactionScope
是一种在方法之间共享事务的简单方法。
由于这些类是特定于实现的,因此我会编写每个类来打开它自己的本机事务。否则,您可以使用ado.net工厂方法从配置文件(提供程序名称)创建相应的类型。
答案 1 :(得分:10)
就个人而言,我喜欢使用SetData和GetData在Thread Local Storage之上存储我当前打开的连接和事务的堆栈。我定义了一个类来管理我与数据库的连接,并允许它使用dispose模式。这节省了我传递连接和事务的需要,这是我认为使代码混乱和复杂化的东西。
我强烈建议反对让它在每次需要数据时打开连接的方法。这将导致一个非常糟糕的情况,即整个应用程序都难以管理事务,并且打开和关闭了太多连接(我知道连接池,从池中查找连接的成本仍然比它更昂贵重用一个对象)
所以我最终得到了这些内容(完全未经测试):
class DatabaseContext : IDisposable {
List<DatabaseContext> currentContexts;
SqlConnection connection;
bool first = false;
DatabaseContext (List<DatabaseContext> contexts)
{
currentContexts = contexts;
if (contexts.Count == 0)
{
connection = new SqlConnection(); // fill in info
connection.Open();
first = true;
}
else
{
connection = contexts.First().connection;
}
contexts.Add(this);
}
static List<DatabaseContext> DatabaseContexts {
get
{
var contexts = CallContext.GetData("contexts") as List<DatabaseContext>;
if (contexts == null)
{
contexts = new List<DatabaseContext>();
CallContext.SetData("contexts", contexts);
}
return contexts;
}
}
public static DatabaseContext GetOpenConnection()
{
return new DatabaseContext(DatabaseContexts);
}
public SqlCommand CreateCommand(string sql)
{
var cmd = new SqlCommand(sql);
cmd.Connection = connection;
return cmd;
}
public void Dispose()
{
if (first)
{
connection.Close();
}
currentContexts.Remove(this);
}
}
void Test()
{
// connection is opened here
using (var ctx = DatabaseContext.GetOpenConnection())
{
using (var cmd = ctx.CreateCommand("select 1"))
{
cmd.ExecuteNonQuery();
}
Test2();
}
// closed after dispose
}
void Test2()
{
// reuse existing connection
using (var ctx = DatabaseContext.GetOpenConnection())
{
using (var cmd = ctx.CreateCommand("select 2"))
{
cmd.ExecuteNonQuery();
}
}
// leaves connection open
}
答案 2 :(得分:8)
出于自动化测试的目的,通常更容易传入。这称为dependency injection。
当您需要编写测试时,您可以创建一个模拟数据库连接对象并传递它而不是真实的。这样,您的自动化测试将不依赖于每次都需要重新填充数据的实际数据库。
答案 3 :(得分:1)
我个人努力尽可能地集中我的数据访问,但是,如果不可能的话,我总是在其他类中打开一个新的连接,因为我发现有太多其他东西可以在通过时阻碍实际的连接对象。
答案 4 :(得分:1)
建立连接可能很昂贵,并可能增加往返。因此,再次,可能,更好的设计是传递连接对象。
我可能会说,因为如果您是Microsoft ADO应用程序,那么您可能正在使用连接池....
答案 5 :(得分:1)
以下是对此问题的更深入了解。我有一个管理数据库连接的类,并有2个实现接口的类。其中一个类用于SQL,另一个用于OLAP。管理器是知道要使用哪个连接的管理器,因此可以将完全连接传递给类型,或者类型可以创建自己的连接。
答案 6 :(得分:1)
您可以毫无问题地传递连接对象(例如Microsoft Enterprise Library允许通过连接传递静态方法调用),或者您可以在外部管理它直到您的设计,没有直接的技术权衡。
如果您的解决方案将被移植到其他数据库(意味着不通过您计划与其他数据库一起使用的SqlConnection),请注意不要传递特定连接的可移植性。
答案 7 :(得分:1)
我建议您区分连接对象及其状态(打开,关闭)。
您可以使用单个方法(或属性)从web.config中读取连接字符串。每次使用相同版本的连接字符串可确保您从连接池中受益。
需要打开连接时调用该方法。在最后一刻,在设置所有SqlCommand属性后,打开连接,使用它,然后关闭它。在C#中,您可以使用using语句来确保连接已关闭。如果没有,请务必关闭finally块中的连接。
答案 8 :(得分:0)
我会使用web.config
<configuration>
<connectionStrings>
<add name="conn1" providerName="System.Data.SqlClient" connectionString="string here" />
<add name="conn2" providerName="System.Data.SqlClient" connectionString="string here" />
</connectionStrings>
</configuration>
然后你可以从应用程序的任何地方引用它