SqlConnection / System.Transactionsを使用したセッションごとの要求

dapper sqlconnection sql-server system.transactions

質問

私は、プロジェクトのために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と簡単に呼び出すことができCurrent.DB 。自動的に動作します。 #if DEBUGすべてのため、これは単体テストにも適しています。


私たちはセッションごとにトランザクションを開始しません。セッションの開始時に更新した場合は、ロックが解除されるまでロックが解除されないため、重大なロック問題が発生します。


人気のある回答

"write"呼び出しでデータベースを呼び出すときに、 TransactionScopeのようなものを必要とするときには、SQL Server Transactionを開始するだけです。

この最近の質問のランダムな例を参照してください。TransactionScope.Complete()が呼び出されない場合でも、ネストされたトランザクションがコミットされるのはなぜですか?

接続を開いてHTTP要求ごとにトランザクションを開始しません 。オンデマンドでのみ。何人かの人々がセッションごとにデータベーストランザクションを開くことをなぜ支持しているのかを理解するのが難しいです。データベーストランザクションが何であるを見ると、

注:私はパターンそれ自体に反対していません。私は、MSDTCを呼び出す不要な、あまりにも長い、クライアント側のデータベーストランザクションに反対しています



ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow