15

プロジェクトで 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();
        }
    }
}
4

2 に答える 2

10

これが私たちの仕事です:

DBと呼ばれるオブジェクトで呼び出される静的を定義しますCurrent

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 
   }

次に、コード内のどこでも、db へのアクセスが必要な場所で簡単に呼び出すだけCurrent.DBで、自動的に機能します。これは、すべてのものがあるため、単体テストにも適してい#if DEBUGます。


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

于 2011-06-02T00:33:47.420 に答える
4

「書き込み」呼び出しでデータベースを呼び出すときに、TransactionScopeなどを使用する必要がある場合にのみ、SQLServerトランザクションを開始します。

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

接続を開いてhttpリクエストごとにトランザクションを開始することはありません。オンデマンドのみ。一部の人々がセッションごとにデータベーストランザクションを開くことを提唱している理由を理解するのに苦労しています。データベーストランザクションとは何かを見ると、まったくのばかです。

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

于 2011-06-01T14:13:26.037 に答える