让我从我当前的设置开始,然后解释我想要实现的目标。我们正在使用 NHibernate 并尝试使用 Ninject 实现 IRepository/IUnitOfWork 模式。理想情况下,它应该适用于使用代码的任何应用程序,无论是 ASP.Net、WCF 还是其他东西。
工作单位
public interface IUnitOfWork
{
object Add(object obj);//all other supported CRUD operations we want to expose
void Commit();
void Rollback();
}
工作单位
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();
}
}
存储库
public interface IRepository<TEntity, TId> where TEntity : class
{
TId Add(TEntity item);//add other missing CRUD operations
}
通用存储库
public class GenericRepository<TEntity, TId> : IRepository<TEntity, TId>
where TEntity : class
{
public TId Add(TEntity item)
{
throw new NotImplementedException();
}
}
我使用 Ninject 作为我的 IOC 容器。目标是在创建 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 impls 使用相同的 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 的东西进行一些小的重组,服务层代码只是废代码,所以我可以在那里非常灵活。