2012-04-03 32 views
5

Tôi có sau Repository ADO NetIDisposable trên một kho tiêm

public class Repository : IRepository, IDisposable 
{ 
    private readonly IUnitOfWork UnitOfWork; 
    private SqlConnection Connection; 

    public Repository(IUnitOfWork unitOfWork, connectionString) 
    { 
     UnitOfWork = unitOfWork; 
     Connection = new SqlConnection(connectionString); 
     Connection.Open(); 
    } 

    public MyObject FindBy(string userName) 
    { 
     //...Ado .Net command.ExecuteReader, etc. 
    } 
} 

kho này được tiêm với một container IoC lên một Dịch vụ tên miền và được sử dụng như sau:

public class UserDomainService : IUserDomainService 
{ 
    private readonly IRepository Repository; 

    public UserDomainService(IRepository repository) 
    { 
     Repository = repository; 
    } 

    public User CreateNewUser(User user) 
    { 
     using(Repository) 
     { 
     var user = Repository.FindBy(user.UserName); 
     if(user != null) 
      throw new Exception("User name already exists!"); 

     Repository.Add(user); 
     Repository.Commit(); 
     } 
    } 
} 

Ý tưởng là tôi luôn đặt đối tượng Repository trong một câu lệnh using để khi kết thúc, kết nối được đóng và xử lý nhưng tôi thấy nó là một vấn đề vì lớp Service Service vẫn còn sống và nếu có cuộc gọi thứ hai, sẽ thất bại vì kho lưu trữ đã bị hủy.

Bây giờ tôi có toàn quyền kiểm soát tất cả mã và tôi chỉ muốn thiết kế các cuộc gọi dịch vụ hạt thô, nhưng có điều gì đó về toàn bộ điều không cảm thấy đúng.

Tôi làm như thế này để tôi có thể tránh được rằng Dịch vụ miền biết về các phương thức OpenConnection và CloseConnection trong kho lưu trữ.

Thiết kế này có kém hay là có cách nào tốt hơn để thực hiện việc này?

Sau khi suy nghĩ: Tất cả cây phụ thuộc đang được tạo ở cấp WCF khi yêu cầu đến và tất nhiên bạn có thể thấy kết nối được mở tại thời điểm đó vì nó xảy ra trong bộ dựng của kho. nó không phải là xấu vì nó chỉ mở cho thời lượng của cuộc gọi cụ thể này. Tôi có đúng về giả định này hay tôi đang làm điều gì đó khủng khiếp xấu bằng cách mở kết nối DB quá sớm trong quá trình này?

+0

'IRepository' có được kết hợp chặt chẽ với 'Repository' không? Có nghĩa là, nó có chứa các phương pháp của nó, chẳng hạn như 'Tìm'? Nếu vậy, giao diện đó có ngụ ý 'IDisposable'? –

+0

Tôi có câu hỏi của riêng tôi có thể liên quan đến điều này: [ServiceContainer, IoC, và các đối tượng dùng một lần] (http://stackoverflow.com/questions/556580/servicecontainer-ioc-and-disposable-objects). –

+1

Tại sao bạn cần 'SqlConnection' trong' Repository'? Có vẻ giống như một cái gì đó cho 'IUnitOfWork' của bạn. – Steven

Trả lời

8

Tiêm một nhà máy tạo ra các trường hợp bạn cần, không phải là một cá thể.

Chụp IRepositoryFactory để bạn có thể tạo IRepository và thải bỏ nó mỗi khi bạn sử dụng. Bằng cách này, không phải dịch vụ miền hoặc nhà máy sẽ cần phải dùng một lần. Ngoài ra, và quan trọng, bạn giữ cho mã trừu tượng bằng cách vẫn tiêm chích thực hiện như trái ngược với mã hóa cứng nó.

public class UserDomainService : IUserDomainService 
{ 
    private readonly IRepositoryFactory RepositoryFactory; 

    public UserDomainService(IRepositoryFactory factory) 
    { 
     RepositoryFactory = factory; 
    } 

    public User CreateNewUser(User user) 
    { 
     using (IRepository repository = RepositoryFactory.Create()) 
     { 
     var user = repository.FindBy(user.UserName); 
     if(user != null) 
      throw new Exception("User name already exists!"); 

     repository.Add(user); 
     repository.Commit(); 
     } 
    } 
} 

Bạn không phải lúc nào cũng phải tiêm loại bạn cần. Khi đọc trên Castle Windsor (có suy nghĩ là đăng ký-giải quyết-phát hành), bạn thấy rằng nếu bạn muốn giải quyết các công cụ tại một thời điểm không xác định trong cuộc sống của ứng dụng, nó được đề nghị sử dụng loại nhà máy.

Bạn biết bạn sẽ cần một Kho lưu trữ nhưng không biết khi. Thay vì yêu cầu một kho lưu trữ, hãy yêu cầu một cái gì đó mà tạo ra chúng. Do đó mức độ trừu tượng được duy trì và bạn không bị rò rỉ bất kỳ việc triển khai nào.

+0

DUH! Tôi không biết tại sao tôi không nghĩ về điều này. Cảm ơn. –

+0

@SergioRomero Đôi khi bạn chỉ cần lùi lại một bước và giải quyết vấn đề với người khác trước khi tự mình đi đến kết luận chính xác. Tôi làm điều đó tất cả các thời gian, nó rất dễ dàng để có được bị mắc kẹt trong vòng tròn thiết kế nếu bạn là đầu gối sâu trong nó tất cả các thời gian :-( –

+0

Bây giờ bạn có một trừu tượng bị rò rỉ. Giải pháp tốt nhất là viết lại Repository để nó tự mở và đóng kết nối cho mỗi giao dịch –

1

Sự cố bạn có là quyền sở hữu. Lớp UserDomainService không tạo ra IRepository, nhưng nó vẫn chiếm quyền sở hữu của cá thể đó, vì nó loại bỏ nó.

Quy tắc chung là người tạo ra một đối tượng nên phân biệt nó. Nói cách khác, người tạo ra vật thể là chủ sở hữu, và chủ nhân sẽ phá hủy vật đó.

Có hai giải pháp cho vấn đề của bạn.

  1. Tạo IRepositoryFactory, như Adam giải thích rõ ràng.Phương thức CreateNewRepository() trên một nhà máy như vậy sẽ truyền đạt rõ ràng rằng người gọi nhận được quyền sở hữu và nên vứt bỏ kho lưu trữ đã tạo.

  2. Cho phép người tạo (và tiêm) kho lưu trữ đó xử lý việc xử lý kho lưu trữ đó. Hoặc bạn làm điều này bằng tay trong dịch vụ WCF của bạn, hoặc bạn sử dụng một khuôn khổ IoC/DI. Trong trường hợp bạn sử dụng một khung công tác DI, có lẽ bạn nên xem xét một yêu cầu của mỗi lần yêu cầu web hoặc một thứ tương tự.

lưu ý cuối, IRepository cụ của bạn IDisposable. Khi chọn giải pháp 2, bạn có thể xóa giao diện IDisposable khỏi IRepository, điều này che giấu thực tế là tài nguyên có liên quan đến ứng dụng. Ẩn IDisposable từ ứng dụng là một điều tốt, vì giao diện đó là một trừu tượng bị rò rỉ. Bạn đã gặp phải điều này, vì gọi số Dispose từ trong ứng dụng, hãy phá vỡ toàn bộ ứng dụng.

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