2016-11-27 6 views
4

Closeメソッドを明示的に呼び出すか、Usingステートメントで接続を実行すると、接続を閉じる必要がありますか?接続をオープンにしておくと、接続の再利用が可能になり、将来のクエリでSQLパフォーマンスが向上しますか?Dapperを使用するときに接続を閉じる

答えて

11

Dapperの最新バージョンを使用していることを前提としています。 Dapperので

、接続を管理する方法は2つあります。

  • は完全に自分自身を管理する: ここでは、開閉接続のために完全に責任があります。これは、ADO.NETを使用しているときに接続を処理する方法と同じです。

  • Dapperのは、それを管理することを許可する: Dapperのは、自動的に(それが開かれていなかった場合)の接続を開き、(それがDapperので開かれた場合)あなたのためにそれを閉じます。これはDataAdapter.Fill()メソッドに似ています。 私は個人的にこの方法をお勧めしません。これは毎回適用されるわけではありません。以下はマルクGravellはこの回答のためcommentの一つにこう言われる、https://stackoverflow.com/a/12629170/5779732

だけでなく、クローズ/技術的に開いているが配置さとは異なっています。個々の通話の周りだけで開閉するつもりなら、あなたはそれを行うこともできます。 より広い粒度(例えば要求ごとに)で開閉するならば、あなたのコードがそれを行い、dapperに対してオープンな接続を渡す方が良いでしょう。

もちろん、1回の接続で複数のクエリを呼び出すことができます。ただし、リソースのリークを避けるために、接続は(Close()Dispose()メソッドを呼び出すか、usingブロックに囲んで)終了する必要があります。接続を閉じると、接続プールに戻ります。接続プールを使用すると、新しい接続コストよりもパフォーマンスが向上します。


接続を処理するだけでなく、トランザクションを管理するためにUnitOfWorkを実装することをお勧めします。 GitHub上のthis優れたサンプルを参照してください。

次のソースコードを参考にしてください。これは私のニーズのために書かれていることに注意してください。それはあなたのためにはうまくいかないかもしれません。

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を受け入れる必要があります。私はConstructorでDependency Injectionを選択します。

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()) 
{ 
    //Your database code here 
    MyRepository myRepository = new MyRepository(dalSession.UnitOfWork);//UoW have no effect here as Begin() is not called. 
    myRepository.Insert(myPoco); 
} 

この方法:トランザクションに

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; 
    } 
} 

トランザクションなしコード、あなたは1つの場所でそれを制御します。

上記のコードのリポジトリの詳細は、hereを参照してください。

UnitOfWorkはちょうどトランザクションよりもmoreです。このコードはトランザクションだけを処理します。このコードを拡張して、追加の役割をカバーすることができます。

+0

私はあなたの意見について完全に同意できません。接続を管理するためにdapperを使用する方がよい場合もあります。私はMarc Gravellをhttps://stackoverflow.com/a/12629170/1262198から引用したいと思っています。 "技術的にオープン/クローズドは処分と異なります。個々のコールの周りを開閉するだけの場合は、あなたがより広い粒度(例えばリクエストごとに)で開閉しているなら、あなたのコードがそれを行い、dapperにオープンな接続を渡す方が良いでしょう。 – Arvand

+0

@Arvand:同意します。私は自分の答えを修正した。私はこれが毎回適用されないかもしれないということを意味します。 –

関連する問題