現在のセットアップから始めて、何を達成しようとしているのかを説明しましょう。NHibernate を使用しており、Ninject で IRepository/IUnitOfWork パターンを実装しようとしています。ASP.Net、WCF、またはその他のコードを使用しているアプリケーションで一般的に機能することが理想的です。
IUnitOfWork
public interface IUnitOfWork
{
object Add(object obj);//all other supported CRUD operations we want to expose
void Commit();
void Rollback();
}
UnitOfWork
public class UnitOfWork : IUnitOfWork
{
private readonly ISessionFactory _sessionFactory;
private readonly ISession _session;
private readonly ITransaction _transaction;
public UnitOfWork(ISessionFactory sessionFactory)
{
_sessionFactory = sessionFactory;
_session = _sessionFactory.OpenSession();
_transaction = _session.BeginTransaction();
}
public object Add(object obj)
{
return _session.Save(obj);
}
public void Commit()
{
if(!_transaction.IsActive)
{throw new Exception("some error");}
_transaction.Commit();
}
public void Rollback()
{
if (!_transaction.IsActive)
{
throw new Exception("some other error");
}
_transaction.Rollback();
}
}
Iリポジトリ
public interface IRepository<TEntity, TId> where TEntity : class
{
TId Add(TEntity item);//add other missing CRUD operations
}
GenericRepository
public class GenericRepository<TEntity, TId> : IRepository<TEntity, TId>
where TEntity : class
{
public TId Add(TEntity item)
{
throw new NotImplementedException();
}
}
IOC コンテナーとして Ninject を使用しています。目標は、UnitOfWork の作成のライフ サイクルで同じ IUnitOfWork を再利用することです。呼び出し元のアプリケーションが何であれ、実装されているライフサイクルが機能するようにしたいのですが、それ以外の場合は、オンラインのほとんどの提案のように InRequestScope を使用しただけです。私はこのようなことをすることができました:
//constructor
public MyService(IUnitOfWork uow, IRepository<User, int> userRepo, IRepository<Cat, int> catRepo)
{
_uow = uow; _userRepo = userRepo; _catRepo = catRepo;
}
//method in same class
public void DoSomeWork()
{
_userRepo.Add(someUser);
_catRepo.Add(someCat);
_uow.Commit();
//rollback on error
}
そして私のバインディングは次のように設定されています:
Bind<IUnitOfWork>.To<UnitOfWork>().InCallScope();
Bind(typeof(IRepository<,>)).To(typeof(GenericRepository<,>));
そして、このバインディング構成は実際には上記の に対して機能MyService
し、コンストラクターで一度 UnitOfWork を作成し、IRepo impl に対しても同じ UnitOfWork を使用します。これは、それらが実際に何層下にあるかに関係ありません。
しかし、私ができるようにしたいのは、IUnitOfWork をアプリケーションから完全に隠すことです。メソッドの上に配置できる TransactionAttribute を提供すると、エントリ時に IUnitOfWork が作成され、その同じインスタンスが、TransactionAttribute のスコープ内の IUnitOfWork に対する今後のすべての要求に挿入されます。そして、それに応じてコミットとロールバックを処理します。したがって、前のコードは次のようになります。
//constructor
public MyService(IRepository<User, int> userRepo, IRepository<Cat, int> catRepo)
{
_uow = uow; _userRepo = userRepo; _catRepo = catRepo;
}
//method in same class
[Transaction]
public void DoSomeWork()
{
_userRepo.Add(someUser);
_catRepo.Add(someCat);
}
このような[Transaction]でメソッドをマークできるようにする、私ができるバインディングセットアップの種類はありますか? 私は IUnitOfWork と IRepository のいくつかのマイナーな再構築にオープンであり、サービス層のコードは単なるスクラップ コードであるため、非常に柔軟に対応できます。