我假设您正在使用最新版本的Dapper。
使用Dapper,有两种方法来管理连接:
完全管理自己:在这里,您完全负责打开和关闭连接。就像使用ADO.NET时如何对待连接一样。
允许Dapper对其进行管理: Dapper自动为您打开连接(如果未打开)并关闭(如果Dapper打开了)。这类似于DataAdapter.Fill()
方法。 我个人不推荐这种方式。这可能并非每次都适用。以下是Marc Gravell在对此答案的评论之一中所说的内容: https : //stackoverflow.com/a/12629170/5779732
很好,技术上的打开/关闭与处理不同。如果您只打算在各个呼叫之间打开/关闭,最好还是让dapper来做。 如果您以更宽的粒度(例如,按请求)打开/关闭,则代码最好这样做,并将打开的连接传递给dapper。
以下是来自这里的报价:
Dapper需要打开连接时会关闭它。因此,如果您只是进行1个快速查询-让Dapper处理。如果您要执行许多操作,则应打开(一次)然后最后关闭,所有查询都放在中间...只是从效率的角度来看。
当然,您可以在单个连接上调用多个查询。但是,应关闭连接(通过调用Close()
, Dispose()
方法或将其封装在using
块中)以避免资源泄漏。关闭连接会将其返回到连接池。参与连接池可提高性能,而不会增加新的连接成本。
除了处理连接之外,我建议您还实现UnitOfWork来管理事务。请在GitHub上参考此优秀示例。
遵循以下源代码可能会对您有所帮助。请注意,这是为我的需要而写的;因此它可能对您不起作用。
public sealed class DalSession : IDisposable
{
public DalSession()
{
_connection = new OleDbConnection(DalCommon.ConnectionString);
_connection.Open();
_unitOfWork = new UnitOfWork(_connection);
}
IDbConnection _connection = null;
UnitOfWork _unitOfWork = null;
public UnitOfWork UnitOfWork
{
get { return _unitOfWork; }
}
public void Dispose()
{
_unitOfWork.Dispose();
_connection.Dispose();
}
}
public sealed class UnitOfWork : IUnitOfWork
{
internal UnitOfWork(IDbConnection connection)
{
_id = Guid.NewGuid();
_connection = connection;
}
IDbConnection _connection = null;
IDbTransaction _transaction = null;
Guid _id = Guid.Empty;
IDbConnection IUnitOfWork.Connection
{
get { return _connection; }
}
IDbTransaction IUnitOfWork.Transaction
{
get { return _transaction; }
}
Guid IUnitOfWork.Id
{
get { return _id; }
}
public void Begin()
{
_transaction = _connection.BeginTransaction();
}
public void Commit()
{
_transaction.Commit();
Dispose();
}
public void Rollback()
{
_transaction.Rollback();
Dispose();
}
public void Dispose()
{
if(_transaction != null)
_transaction.Dispose();
_transaction = null;
}
}
interface IUnitOfWork : IDisposable
{
Guid Id { get; }
IDbConnection Connection { get; }
IDbTransaction Transaction { get; }
void Begin();
void Commit();
void Rollback();
}
现在,您的存储库应该以某种方式接受此UnitOfWork。我选择使用构造函数进行依赖注入。
public sealed class MyRepository
{
public MyRepository(IUnitOfWork unitOfWork)
{
this.unitOfWork = unitOfWork;
}
IUnitOfWork unitOfWork = null;
//You also need to handle other parameters like 'sql', 'param' ect. This is out of scope of this answer.
public MyPoco Get()
{
return unitOfWork.Connection.Query(sql, param, unitOfWork.Transaction, .......);
}
public void Insert(MyPoco poco)
{
return unitOfWork.Connection.Execute(sql, param, unitOfWork.Transaction, .........);
}
}
然后您这样称呼它:
进行交易:
using(DalSession dalSession = new DalSession())
{
UnitOfWork unitOfWork = dalSession.UnitOfWork;
unitOfWork.Begin();
try
{
//Your database code here
MyRepository myRepository = new MyRepository(unitOfWork);
myRepository.Insert(myPoco);
//You may create other repositories in similar way in same scope of UoW.
unitOfWork.Commit();
}
catch
{
unitOfWork.Rollback();
throw;
}
}
没有交易:
using(DalSession dalSession = new DalSession())
{
//Your database code here
MyRepository myRepository = new MyRepository(dalSession.UnitOfWork);//UoW have no effect here as Begin() is not called.
myRepository.Insert(myPoco);
}
这样,您可以在一个位置进行控制,而不是直接在调用代码中公开连接。
可以在此处找到上述代码中有关存储库的更多详细信息。
请注意UnitOfWork
是更不仅仅是一个交易。这段代码只处理事务。您可以扩展此代码以涵盖其他角色。