我刚刚开始使用Dapper进行项目,在过去几年中大多使用过NHibernate和EF等ORM.
通常在我们的Web应用程序中,我们实现每个请求的会话,在请求开始时开始一个事务,并在最后提交它.
我们应该在与sqlConnection / System.Transactions直接工作时做类似的事情吗?
StackOverflow如何做?
解
接受@gbn和@Sam Safron的建议我没有使用交易.在我的情况下,我只是读取查询,所以似乎没有真正的要求使用事务(与我已经被告知有关隐式事务).
我创建一个轻量级的会话接口,以便我可以根据请求使用连接.这对我来说是非常有益的,与Dapper一样,我经常需要创建一些不同的查询来构建一个对象,而不是共享相同的连接.
对每个请求进行连接的处理工作由IoC容器(StructureMap)完成:
public interface ISession : IDisposable { IDbConnection Connection { get; } } public class DbSession : ISession { private static readonly object @lock = new object(); private readonly ILogger logger; private readonly string connectionString; private IDbConnection cn; public DbSession(string connectionString,ILogger logger) { this.connectionString = connectionString; this.logger = logger; } public IDbConnection Connection { get { return GetConnection(); } } private IDbConnection GetConnection() { if (cn == null) { lock (@lock) { if (cn == null) { logger.Debug("Creating Connection"); cn = new sqlConnection(connectionString); cn.Open(); logger.Debug("Opened Connection"); } } } return cn; } public void Dispose() { if (cn != null) { logger.Debug("Disposing connection (current state '{0}')",cn.State); cn.Dispose(); } } }
解决方法
这就是我们所做的:
我们在称为Current的对象上定义了一个静态的称为DB
public static DBContext DB { var result = GetContextItem<T>(itemKey); if (result == null) { result = InstantiateDB(); SetContextItem(itemKey,result); } return result; } public static T GetContextItem<T>(string itemKey,bool strict = true) { #if DEBUG // HttpContext is null for unit test calls,which are only done in DEBUG if (Context == null) { var result = CallContext.GetData(itemKey); return result != null ? (T)result : default(T); } else { #endif var ctx = HttpContext.Current; if (ctx == null) { if (strict) throw new InvalidOperationException("GetContextItem without a context"); return default(T); } else { var result = ctx.Items[itemKey]; return result != null ? (T)result : default(T); } #if DEBUG } #endif } public static void SetContextItem(string itemKey,object item) { #if DEBUG // HttpContext is null for unit test calls,which are only done in DEBUG if (Context == null) { CallContext.SetData(itemKey,item); } else { #endif HttpContext.Current.Items[itemKey] = item; #if DEBUG } #endif }
在我们的例子中,InstantiateDB返回一个L2S上下文,但是在你的情况下,它可能是一个打开的sqlConnection或其他任何东西.
在我们的应用程序对象上,我们确保我们的连接在请求结束时关闭.
protected void Application_EndRequest(object sender,EventArgs e) { Current.DisposeDB(); // closes connection,clears context }
然后在你需要访问数据库的代码中的任何地方,你简单地调用Current.DB和东西自动工作.这也是单元测试友好,由于所有#if DEBUG的东西.
我们不会在每个会话中开始任何交易,如果我们在会话开始时进行了更新,我们会遇到严重的锁定问题,因为锁将不会被释放直到结束.