让我从我当前的设置开始,然后解释我想实现的目标。我们使用NHibernate并试图用Ninject实现IRepository/IUnitOfWork模式。理想情况下,它应该适用于任何使用代码的应用程序,无论是ASP.Net,WCF还是其他。ninject注入iunitofwork到存储库作用域属性
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();
}
}
IRepository
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();
}
}
我使用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相同的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);
}
是否有任何形式的结合设置我能做到这将使我来标记与[交易]的方法也是这样吗?我愿意对IUnitOfWork和IRepository进行一些小的重构,而服务层代码只是废料代码,所以我可以在那里非常灵活。
我们目前使用'PostSharp'(V2.1可悲)在其他组件,所以我知道我会用它来实现AOP。我的想法是,我的方面的OnEntry会开始一个新的'UnitOfWork'(我会忽略尝试附加到现有的),但我如何确保创建的'UnitOfWork'是注入每个' IRepository'?我是否需要通过将方面的'UnitOfWork'粘贴到某种上下文机制(ThreadLocal/SynchronizationContext,就像您所提到的)? – cjablonski76 2014-10-31 13:13:14
既然(至少这就是我干涉的内容),你不能也不想将“Session”的生命周期与使用它的对象的生命周期联系起来,你确实需要使用像ThreadLocal这样的上下文机制或SynchronizationContext。 – BatteryBackupUnit 2014-10-31 13:44:33
如果你不想使用这样的上下文机制,每次执行DoSomeWork时都需要创建一个新的用户回购,cat回购等。你可能最终会重新创建你的对象图中相当大的一部分(取决于设计...)。有了上下文机制,你只能创建'Session',但你仍然需要这样做(通过'IUnitOfWork.Begin()'或创建一个新的'IUnitOfWork'实例)。 – BatteryBackupUnit 2014-10-31 13:47:12