.NET Core Dependency Injectionを使用して、アプリケーションの起動時にSqlConnection
オブジェクトをインスタンス化し、それをリポジトリに挿入することを計画しています。このSqlConnection
は、リポジトリの実装内のデータベースからデータを読み書きするためにDapperによって使用されます。 Dapperでasync
呼び出しを使用します。
問題は、SqlConnection
を一時的なものとして注入するか、シングルトンとして注入するかです。 async
を使用したいという事実を考えると、Dapperが内部でいくつかの分離コンテナーを実装し、シングルトンのスコープがDapperが内部で使用するスコープ内にラップされない限り、一時的なものを使用すると思います。
Dapperを使用する場合のSqlConnectionオブジェクトの存続期間に関する推奨事項/ベストプラクティスはありますか?私が見逃しているかもしれない注意事項はありますか?
前もって感謝します。
SQL接続をシングルトンとして提供する場合、MARSを有効にしない限り、同時に複数の要求を処理できません。これには、MARSにも制限があります。ベストプラクティスは、一時的なSQL接続を使用して、適切に破棄されるようにすることです。
私のアプリケーションでは、IDbConnectionFactory
ステートメント内で接続を作成するために使用されるリポジトリにカスタムusing
を渡します。この場合、ヒープ自体の割り当てを減らすために、リポジトリ自体をシングルトンにすることができます。
回答もコメントも、@ Andrii Litvinovに同意します。
この場合、データソース固有の接続ファクトリのアプローチを使用します。
同じアプローチで、私は別の方法-UnitOfWorkについて言及しています。
this の回答からDalSession
およびUnitOfWork
を参照してください。これは接続を処理します。
this 回答からBaseDal
を参照してください。これはRepository
(実際にはBaseRepository
)の実装です。
UnitOfWork
は一時的なものとして挿入されます。DalSession
を作成することで処理できます。UnitOfWork
はBaseDal
に挿入されます。Dapperを使用する場合のSqlConnectionオブジェクトの有効期間に関する推奨事項/ベストプラクティスはありますか?
ほとんどの開発者が同意することの1つは、接続は可能な限り短期間である必要があるということです。ここには2つのアプローチがあります。
using
ブロックで接続を囲みます。アクションをグループ化したくない限り、これは良いアプローチです。アクションをグループ化したい場合でも、ほとんどの場合トランザクションを使用できます。using
ブロックを使用できません。ソリューションは以下のUnitOfWorkです。すばらしい質問で、すでに2つのすばらしい答えがあります。私は最初これに戸惑い、リポジトリをマネージャーにカプセル化するという問題を解決する次の解決策を思いつきました。マネージャ自体は、接続文字列を抽出し、それをリポジトリに挿入する責任があります。
私はこの方法を使用して、リポジトリを個別にテストできるようにしました。たとえば、モックコンソールアプリを使用すると、はるかに簡単になり、いくつかの大規模プロジェクトでこのパターンをたどることができました。私は確かにテスト、依存性注入、または実際には何も専門家ではありません!
私が私に残した主な質問は、DbServiceをシングルトンにするかどうかです。私の論理的根拠は、DbService
にカプセル化されたさまざまなリポジトリを常に作成および破棄することはあまり意味がなかったことであり、それらはすべてステートレスであるため、それらを「ライブ」にすることに大きな問題は見られませんでした。ただし、これは完全に無効なロジックである可能性があります。
編集:既製のソリューションが必要な場合は、 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());
}
}