sql-server – 使用SqlConnection / System.Transactions的Session-Per-Request

我刚刚开始使用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的东西.

我们不会在每个会话中开始任何交易,如果我们在会话开始时进行了更新,我们会遇到严重的锁定问题,因为锁将不会被释放直到结束.

相关文章

SELECT a.*,b.dp_name,c.pa_name,fm_name=(CASE WHEN a.fm_n...
if not exists(select name from syscolumns where name=&am...
select a.*,pano=a.pa_no,b.pa_name,f.dp_name,e.fw_state_n...
要在 SQL Server 2019 中设置定时自动重启,可以使用 Window...
您收到的错误消息表明数据库 &#39;EastRiver&#39; 的...
首先我需要查询出需要使用SQL Server Profiler跟踪的数据库标...