2017-03-21 4 views
4

私は.NETコア依存性注入を使用してアプリケーションの起動時にSqlConnectionオブジェクトをインスタンス化しています。これをリポジトリに挿入する予定です。このSqlConnectionは、リポジトリの実装内でデータベースからデータを読み書きするためにDapperによって使用されます。 Dapperでasyncの呼び出しを使用します。Dapper with .NETコア注入SqlConnectionの有効期間/スコープ

質問:私はSqlConnectionを一時的またはシングルトンとして注入する必要がありますか?私がasyncを使用したいという事実を考えると、Dapperが内部的にいくつかの独立したコンテナを実装していない限り、一時的な使用が考えられます。

Dapperを使用しているときに、SqlConnectionオブジェクトの存続期間に関する推奨事項やベストプラクティスはありますか?私は行方不明の警告がありますか?

ありがとうございます。

答えて

3

シングルトンとしてSQL接続を提供する場合、MARSを有効にしない限り複数のリクエストを同時に処理することはできません。また、制限もあります。ベストプラクティスは、一時的なSQL接続を使用し、適切に処理されていることを確認することです。

私のアプリケーションでは、IDbConnectionFactoryusingステートメント内で接続を作成するために使用されるリポジトリに渡します。この場合、ヒープ上の割り当てを減らすためにリポジトリ自体をシングルトンにすることができます。

+0

私は工場のアプローチを好むが、どのように1は、複数のデータソースの(データベース)とのシナリオを処理するだろう、単一のアプリケーションのために?データベースごとに子の 'ISomeDbConnectionFactory'を作成し、追加のパラメータをファクトリに渡して、どの接続を作成する必要があるかを判断します。あるいはもっとエレガントなもの? –

+1

私は、同じリポジトリが単一のデータソースへの接続を使用すると仮定します。この場合、私はデータソース固有の接続ファクトリのアプローチに行きます。ファクトリのインタフェースは、DB固有の実装と同じにすることができます。 –

+0

MARSを有効にしても、同じ 'SqlConnection'を使用して複数の同時リクエストを処理することはできません。 [MSDN](https://msdn.microsoft.com/en-us/library/h32h3abf(v = vs.110).aspx)によると: "MARS操作はスレッドセーフではありません"。 – Steven

3

私は@Andrii Litvinovに賛成します。回答とコメントの両方です。

この場合、私はデータソース固有の接続ファクトリのアプローチに行きます。

同じアプローチで、私は別の方法 - UnitOfWorkを言及しています。

DalSessionUnitOfWorkthisから回答してください。これは接続を処理します。
BaseDalthisから回答してください。これは私の実装であるRepository(実際にはBaseRepository)です。

  • UnitOfWorkが一時的に注入される。
  • データソースごとに別々のDalSessionを作成すると、複数のデータソースを処理できます。
  • UnitOfWorkは、BaseDalに注入される。

Dapperのを扱うときにSqlConnectionオブジェクトの寿命に関する推奨事項/ベストプラクティスはありますか?

ほとんどの開発者が同意することは、接続はできるだけ短命でなければならないということです。私はここで2つのアプローチを参照してください:

  1. アクションごとの接続。
    これは、接続の最短寿命になります。あなたは各アクションのブロックをusingブロックで囲みます。これは、アクションをグループ化したくない限り、良いアプローチです。アクションをグループ化する場合でも、ほとんどの場合、トランザクションを使用できます。
    問題は、複数のクラス/メソッドにわたってアクションをグループ化する場合に発生します。ブロックusingは使用できません。ソリューションは以下のようにUnitOfWorkです。
  2. 単位作業単位の接続。
    作業ユニットを定義します。これはアプリケーションごとに異なります。 Webアプリケーションでは、 "リクエストごとの接続"が広く使われています。
    一般的に、私たちが全体として実行したいアクションのグループが(ほとんどの場合、)存在するので、これはより理にかなっています。これは上で提供した2つのリンクで説明されています。
    このアプローチのもう1つの利点は、アプリケーション(DALを使用する)が接続の使用方法をより詳細に制御できることです。そして、私の理解では、アプリケーションはどのように接続を使用すべきかをDALよりよく知っています。
1

偉大な質問、すでに2つの大きな答え。私はまずこれに困惑し、問題を解決するために以下の解決策を思いつきました。マネージャーにリポジトリをカプセル化しています。マネージャ自体は、接続文字列を抽出し、それをリポジトリに注入する責任があります。

私は、モックコンソールアプリケーションのようにリポジトリを個々にテストする方がはるかに簡単であるというこのアプローチを見つけました。そして、私はいくつかの大規模なプロジェクトでこのパターンに従って多くの運があります。私は確かにテスト、依存症注入、または何かの専門家ではありません本当に何か!

私が尋ねた主な質問は、DbServiceがシングルトンであるべきかどうかです。私の理論的根拠は、DbServiceにカプセル化されたさまざまなリポジトリを常に作成して破壊する点はあまりなく、ステートレスなので、「生きる」ことに大きな問題は見られませんでした。これは完全に無効なロジックかもしれませんが。

EDIT:あなたは既製のソリューションをしたいなら、以下のようにGitHub

に私のDapperのリポジトリの実装をチェックアウトするリポジトリマネージャが構成されています

/* 
* Db Service 
*/ 
public interface IDbService 
{ 
    ISomeRepo SomeRepo { get; } 
} 

public class DbService : IDbService 
{ 
    readonly string connStr; 
    ISomeRepo someRepo; 

    public DbService(string connStr) 
    { 
     this.connStr = connStr; 
    } 

    public ISomeRepo SomeRepo 
    { 
     get 
     { 
      if (someRepo == null) 
      { 
       someRepo = new SomeRepo(this.connStr); 
      } 

      return someRepo; 
     } 
    } 
} 

サンプルリポジトリが構造化されるだろう

/* 
* Mock Repo 
*/ 
public interface ISomeRepo 
{ 
    IEnumerable<SomeModel> List(); 
} 

public class SomeRepo : ISomeRepo 
{ 
    readonly string connStr; 

    public SomeRepo(string connStr) 
    { 
     this.connStr = connStr; 
    } 

    public IEnumerable<SomeModel> List() 
    { 
     //work to return list of SomeModel 
    } 
} 

それをすべてアップ配線:

/* 
* Startup.cs 
*/ 
public IConfigurationRoot Configuration { get; } 

public void ConfigureServices(IServiceCollection services) 
{ 
    //...rest of services 

    services.AddSingleton<IDbService, DbService>(); 

    //...rest of services 
} 

そして最後に、それを使用して:

public SomeController : Controller 
{ 
    IDbService dbService; 

    public SomeController(IDbService dbService) 
    { 
     this.dbService = dbService; 
    } 

    public IActionResult Index() 
    { 
     return View(dbService.SomeRepo.List()); 
    } 
} 
関連する問題