2012-04-04 36 views
6

Tôi đã triển khai kho lưu trữ Chung đầu tiên của mình trong ứng dụng MVC. Hoạt động tốt nhưng làm thế nào để đặt kho trong phạm vi giao dịch?Kho lưu trữ và giao dịch chung

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(); 

} 


} 

Phương pháp tốt nhất để bao bọc mã vùng chứa với Phạm vi giao dịch trong hành động Chèn người dùng là gì?

+0

Ngoài ra hãy xem [bài viết này] (http://www.cuttingedge.it/blogs/steven/pivot/entry.php?id=89). – Steven

Trả lời

9

Bạn đang thiếu một sự trừu tượng ở đây. Bạn nên đặt tất cả các logic nghiệp vụ của bạn bên trong các trình xử lý lệnh và tạo một trình xử lý lệnh để thực hiện hành vi giao dịch. This article mô tả làm thế nào để làm điều này, nhưng trong ngắn hạn:

  1. Xác định một giao diện ICommandHandler<TCommand>:

    public interface ICommandHandler<TCommand> 
    { 
        void Handle(TCommand command); 
    } 
    
  2. Tạo lệnh xác định hợp đồng của một hoạt động kinh doanh. Các lệnh chỉ đơn giản là DTOs (chỉ với dữ liệu và không có hành vi). Ví dụ:

    public class ShipOrderCommand 
    { 
        public int OrderId { get; set; } 
    
        public ShippingInfo Info { get; set; } 
    } 
    
  3. Thực hiện xử lý lệnh đó sẽ chứa các logic kinh doanh/hành vi đối với những lệnh:

    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. 
        } 
    } 
    
  4. Hãy điều khiển MVC của bạn phụ thuộc vào ICommandHandler<T> trừu tượng:

    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 
         }); 
        } 
    } 
    
  5. Xác định trình trang trí chung để triển khai logic giao dịch:

    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(); 
         } 
        } 
    } 
    
  6. Đảm bảo rằng mỗi ShipOrderCommandHandler được trang trí với một TransactionalCommandHandlerDecorator và tiêm vào ShipOrderController. Bạn có thể làm điều này với container DI yêu thích của bạn, hoặc bằng tay:

    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); 
    } 
    

Với điều này trong nơi bạn có thể chạy tất cả các logic kinh doanh của bạn bên trong một giao dịch, mà không cần logic kinh doanh phải nhận thức được cái đó.

+0

Hoặc ... bạn có thể xử lý phạm vi giao dịch ở cấp BeginRequest/EndRequest (vì đây là một ứng dụng web, sau khi tất cả), và tránh hàng trăm dòng trừu tượng không cần thiết và mã phức tạp. – Chris

+2

@ Chris: Tôi không đồng ý với hai điểm. 1. Đó là trừu tượng không cần thiết. Mã này tuân thủ các nguyên tắc SOLID và sẽ giữ cho ứng dụng của bạn có thể kiểm tra, có thể mở rộng và duy trì được. 2. Đó là hàng trăm dòng mã bổ sung. Trong thực tế, nó sẽ giúp bạn tiết kiệm từ việc có nhiều dòng mã trùng lặp. – Steven

+0

@Steven có lẽ bạn có ví dụ mã làm thế nào để tiêm dụ mới của TransactionalCommandHandlerDecorator bằng cách sử dụng Ninject? – Tomas

1

Có một mẫu gọi là Đơn vị công việc. Đây là an explanation.

+0

+1 UOW thực sự là mẫu áp dụng tại đây. –

+0

DBContext của EntityFramework * là đơn vị công việc của bạn! – Mardoxx

Các vấn đề liên quan