作業パターンのナベナートユニットとninjectの正しい使用
-
28-09-2019 - |
質問
私は次の実装を持っていますが、それがセッションや取引のためにNhibernateを正しく使用するかどうかについてのフィードバックを望みます。
public interface IUnitOfWork : IDisposable
{
ISession CurrentSession { get; }
void Commit();
void Rollback();
}
public class UnitOfWork : IUnitOfWork
{
private readonly ISessionFactory _sessionFactory;
private readonly ITransaction _transaction;
public UnitOfWork(ISessionFactory sessionFactory)
{
_sessionFactory = sessionFactory;
CurrentSession = _sessionFactory.OpenSession();
_transaction = CurrentSession.BeginTransaction();
}
public ISession CurrentSession { get; private set; }
public void Dispose()
{
CurrentSession.Close();
CurrentSession = null;
}
public void Commit()
{
_transaction.Commit();
}
public void Rollback()
{
if (_transaction.IsActive) _transaction.Rollback();
}
}
ニッジバインディング
Bind<IUnitOfWork>().To<UnitOfWork>().InTransientScope();
Bind<ISessionFactory>().ToProvider<NHibernateSessionFactoryProvider>().InSingletonScope();
Bind<IRepository>().To<Repository>().InTransientScope();
使用の例は次のとおりです。
public class Repository : IRepository
{
private readonly ISessionFactory _sessionFactory;
public Repository(ISessionFactory sessionFactory)
{
_sessionFactory = sessionFactory;
}
public void Add(IObj obj)
{
using (var unitOfWork = new UnitOfWork(_sessionFactory))
{
unitOfWork.CurrentSession.Save(obj);
unitOfWork.Commit();
}
}
}
以前の実装では、iunitofworkをリポジトリコンストラクターに挿入します。
public Repository(IUnitOfWork unitOfWork)
{...
ただし、dispose()メソッドは、この例外をスローするために後続の呼び出しを引き起こすことはありません。
解決
最初の観察:リポジトリは作業単位をコミットしてはなりません。これは、作業パターンの単位の全体のポイントを打ち負かします。リポジトリ内で変更をすぐに保存することで、Nhibernateセッションを「マイクロ管理」しています。
作業単位は、アプリケーション/サービスレイヤーで、スタックの上でより高く参照する必要があります。これにより、さまざまなリポジトリで潜在的にいくつかのアクションを実行するアプリケーションコードを作成できますが、最終的にはすべてを一度にコミットできます。
Unitofworkクラス自体は大丈夫に見えますが、本当に必要かどうかを自問する必要があります。 nhibernateでは、isessionはあなたの仕事の単位です。あなたのUnitofworkクラスは多くの価値を追加していないようです(特に、とにかくcurrentsessionプロパティを公開しているため)
しかし、あなたはそれが生涯であることを考える必要があります。この点については間違っていると思います。セッションのライフタイム管理は、開発するアプリケーションのタイプに依存します。Webアプリでは、通常、リクエストごとに作業単位が必要です(「リクエストごとのnhibernateセッション」でグーグルで検索することができます)。デスクトップアプリでは、少し複雑です。ほとんどの場合、「画面ごとのセッション」または「ビジネストランザクションごとの会話」が必要になります。
他のヒント
私はほとんどCRUDタイプのアプリケーションを持っています、そして、リポジトリパターンで作業単位を実装しましたが、セッション/トランザクションの分割から実際に逃れることはできませんでした。セッションとトランザクションには、寿命が異なります。デスクトップの世界では、セッションは通常「画面ごと」であり、トランザクションは「ユーザーごとのアクション」です。
これの詳細 優れた記事.
だから私が終わったのは:
IUnitOfWork
- >セッションをラップ、実装IDisposable
IAtomicUnitOfWork
- >トランザクションをラップ、実装IDisposable
IRepository
- > get、保存、削除、クエリアクセスを提供します
私はあなたが必要とするようにそれを作りました IUnitOfWork
構築する IAtomicUnitOfWork
そして、あなたは必要です IAtomicUnitOfWork
構築する IRepository
, 、そのため、適切なトランザクション管理を実施します。それは本当に私が自分のインターフェイスを実装することで得たすべてです。
Jeroenhが言ったように、あなたはほぼ同様に使用しています ISession
と ITransaction
しかし、最終的には、私が定義したインターフェイスに対してすべてのコードを書くことが少し良いと感じました。
答えの重要な部分は、トランザクションサイズになりたいものにあります。現在(Jeroenhが示しているように)、トランザクションはリポジトリのメソッドの呼び出しです。これは非常に小さく、おそらく必要ではありません。 ASP.MVCアプリケーションを作成し、単一のHTTP要求からすべてを含むトランザクションサイズを使用します。これは、複数のデータベースの読み取り/更新である可能性があります。私は同じ仕事の単位を使用しており、IOCにはninjectを使用しています。見てください、多分何かがあなたの問題に役立つでしょう:
http://bobcravens.com/2010/06/the-repository-pattern-with-linq-to-fluent-nhibernate-and-mysql/
http://bobcravens.com/2010/07/using-nhibernate-in-asp-net-mvc/
http://bobcravens.com/2010/09/the-repository-pattern-part-2/
http://bobcravens.com/2010/11/using-ninject-to-manage-critical-resources/
お役に立てれば。
ボブ