我在MVC应用程序中实现了我的第一个Generic存储库。工作正常,但如何将存储库放在事务范围?
public interface IRepository<TEntity> where TEntity : class
{
List<TEntity> FetchAll();
IQueryable<TEntity> Query { get; }
void Add(TEntity entity);
void Delete(TEntity entity);
void Save();
}
public class Repository<T> : IRepository<T> where T : class
{
private readonly DataContext _db;
public Repository(DataContext db)
{
_db = db;
}
#region IRepository<T> Members
public IQueryable<T> Query
{
get { return _db.GetTable<T>(); }
}
public List<T> FetchAll()
{
return Query.ToList();
}
public void Add(T entity)
{
_db.GetTable<T>().InsertOnSubmit(entity);
}
public void Delete(T entity)
{
_db.GetTable<T>().DeleteOnSubmit(entity);
}
public void Save()
{
_db.SubmitChanges();
}
#endregion
}
private void RegisterDependencyResolver()
{
var kernel = new StandardKernel();
var connectionString = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
kernel.Bind(typeof(DataContext)).ToMethod(context => new DataContext(connectionString));
kernel.Bind(typeof(IRepository<>)).To(typeof(Repository<>));
DependencyResolver.SetResolver(new NinjectDependencyResolver(kernel));
}
public class AdminController : Controller
{
private readonly IRepository<User> _userRepository;
private readonly IRepository<Order> _orderRepository;
public AdminController(IRepository<User> userRepository, IRepository<Order> orderRepository)
{
_userRepository = userRepository;
_orderRepository = orderRepository;
}
public ActionResult InsertUser(UserViewModel model)
{
//Skip Code
//Do not commit data to database if _orderRepository is failed to save data
_userRepository.Add(user);
_userRepository.Save();
//Skip Code
_orderRepository.Add(order);
_orderRepository.Save();
}
}
在InsertUser操作中使用事务范围包装存储库代码的最佳方法是什么?
答案 0 :(得分:8)
你在这里错过了抽象。您应该将所有业务逻辑放在命令处理程序中,并创建一个实现事务行为的命令处理程序装饰器。 This article描述了如何执行此操作,但简而言之:
定义ICommandHandler<TCommand>
界面:
public interface ICommandHandler<TCommand>
{
void Handle(TCommand command);
}
创建定义业务操作合同的命令。命令只是DTOs(只有数据,没有行为)。例如:
public class ShipOrderCommand
{
public int OrderId { get; set; }
public ShippingInfo Info { get; set; }
}
实现将包含这些命令的业务逻辑/行为的命令处理程序:
public class ShipOrderCommandHandler
: ICommandHandler<ShipOrderCommand>
{
private readonly IRepository<Order> repository;
public ShipOrderCommandHandler(
IRepository<Order> repository)
{
this.repository = repository;
}
public void Handle(ShipOrderCommand command)
{
// do some useful stuf with the command and repository.
}
}
让您的MVC控制器依赖于ICommandHandler<T>
抽象:
public ShipOrderController : Controller
{
private readonly ICommandHandler<ShipOrderCommand> handler;
public ShipOrderController(
ICommandHandler<ShipOrderCommand> handler)
{
this.handler = handler;
}
public void Ship(int orderId, ShippingInfo info)
{
this.handler.Handle(new ShipOrderCommand
{
OrderId = orderId,
Info = info
});
}
}
定义实现事务逻辑的通用装饰器:
public TransactionalCommandHandlerDecorator<TCommand>
: ICommandHandler<TCommand>
{
private ICommandHandler<TCommand> decoratedHandler;
public TransactionalCommandHandlerDecorator(
ICommandHandler<TCommand> decoratedHandler)
{
this.decoratedHandler = decoratedHandler;
}
public void Handle(TCommand command)
{
using (var scope = new TransactionScope())
{
this.decoratedHandler.Handle(command);
scope.Complete();
}
}
}
确保每个ShipOrderCommandHandler
都装饰有TransactionalCommandHandlerDecorator
并注入ShipOrderController
。您可以使用您喜欢的DI容器或手动执行此操作:
protected override IController GetControllerInstance(
RequestContext requestContext, Type controllerType)
{
if (controllerType == typeof(ShipOrderController))
{
return new ShipOrderController(
new TransactionalCommandHandlerDecorator<ShipOrderCommand>(
new ShipOrderCommandHandler(
new OrderRepository())));
}
return base.GetControllerInstance(requestContext, controllerType);
}
有了这个,您就可以在事务中运行所有业务逻辑,而无需业务逻辑了解它。
答案 1 :(得分:1)
有一种称为工作单元的模式。这是an explanation。