2009-01-05 15 views
16

Tôi tự hỏi điều gì sẽ là prectice tốt nhất liên quan đến các kết nối chính đến cơ sở dữ liệu trong ứng dụng .Net (ADO.NET nhưng tôi đoán thực hành nên là tương tự cho bất kỳ lớp dữ liệu nào). Tôi có nên tạo một kết nối cơ sở dữ liệu và tuyên truyền nó trong suốt ứng dụng của tôi, hay tốt hơn là chỉ cần truyền các chuỗi kết nối/nhà máy và tạo một kết nối đặc biệt, khi cần thiết.Thực hành tốt nhất để chia sẻ IDbConnection hoặc chuỗi kết nối/nhà máy trong mã .Net của bạn

Khi tôi hiểu được sự hoàn hảo, không cho phép tôi khôi phục các kết nối bị hỏng một cách dễ dàng (chỉ cần tạo kết nối mới) nhưng sau đó lại là đối tượng kết nối. tạo một kết nối mới cho mọi hoạt động (không phải lệnh SQL, nhưng hoạt động ứng dụng) tạo ra mã trùng lặp, bổ sung và cảm thấy như lãng phí thời gian/tài nguyên (?).

Bạn nghĩ gì về 2 trường hợp này, khuyết điểm/ưu điểm của họ và cách tiếp cận nào bạn đang sử dụng trong các ứng dụng thực tế của mình?

Cảm ơn

Trả lời

11

Tôi thấy mình cần phải vượt qua một đối tượng kết nối để tôi có thể cho phép một số đối tượng kinh doanh lưu chính mình vào cơ sở dữ liệu bên trong một giao dịch duy nhất.

Nếu mỗi đối tượng kinh doanh phải tạo SQLConnection riêng của mình vào cơ sở dữ liệu, giao dịch sẽ chuyển sang giao dịch phân phối và tôi muốn tránh điều đó.

Tôi không thích phải truyền đối tượng SQLConnection làm tham số để lưu đối tượng, vì vậy tôi đã tạo ConnectionManager xử lý việc tạo đối tượng SQLConnection cho tôi, theo dõi việc sử dụng đối tượng SQLConnection và ngắt kết nối đối tượng SQLConnection không sử dụng.

Dưới đây là một số mã như một ví dụ về ConnectionManager:

public class ConnectionManager: IDisposable 
{ 
    private ConnectionManager instance; 

    [ThreadStatic] 
    private static object lockObject; 
    private static Object LockObject 
    { 
     get 
     { 
      if (lockObject == null) 
       lockObject = new object(); 
      return lockObject; 
     } 
    } 

    [ThreadStatic] 
    private static Dictionary<string, ConnectionManager> managers; 
    private static Dictionary<string, ConnectionManager> Managers 
    { 
     get 
     { 
      if (managers == null) 
       managers = new Dictionary<string, ConnectionManager>(); 
      return managers; 
     } 
    } 

    private SqlConnection connection = null; 
    private int referenceCount; 
    private string name; 


    public static ConnectionManager GetManager(string connectionName) 
    { 
     lock (LockObject) 
     { 
      ConnectionManager mgr; 
      if (Managers.ContainsKey(connectionName)) 
      { 
       mgr = Managers[connectionName]; 
      } 
      else 
      { 
       mgr = new ConnectionManager(connectionName); 
       Managers.Add(connectionName, mgr); 
      } 

      mgr.AddRef(); 
      return mgr; 
     } 
    } 

    private ConnectionManager(string connectionName) 
    { 
     name = connectionName; 
     connection = new SqlConnection(GetConnectionString(connectionName)); 
     connection.Open(); 
    } 

    private string GetConnectionString(string connectionName) 
    { 
     string conString = Configuration.ConnectionString; 
     return conString; 
    } 

    public SqlConnection Connection 
    { 
     get { return connection; } 
    } 

    private void AddRef() 
    { 
     referenceCount += 1; 
    } 

    private void DeRef() 
    { 
     lock (LockObject) 
     { 
      referenceCount -= 1; 
      if (referenceCount == 0) 
      { 
       connection.Dispose(); 
       Managers.Remove(name); 
      } 
     } 
    } 

#region IDisposable Members 

    public void Dispose() 
    { 
     Dispose(true); 
    } 

    protected virtual void Dispose(bool disposing) 
    { 
     if (disposing) 
     { 
      DeRef(); 
     } 
    } 

    ~ConnectionManager() 
    { 
     Dispose(false); 
    } 

#endregion 

} 

Dưới đây là làm thế nào tôi sẽ sử dụng nó từ một đối tượng kinh doanh:

public void Save() 
{ 
    using (ConnectionManager mrg = ConnectionManager.GetManager("SQLConnectionString") 
    { 
     using (SQLCommand cmd = new SQLCommand) 
     { 
      cmd.connection = mgr.Connection 
      // More ADO Code Here 
     } 

     _childObject.Save(); //this child object follows the same pattern with a using ConnectionManager. 
    } 
} 

tôi lưu một đối tượng kinh doanh và tất cả của nó trẻ em được lưu cũng như sử dụng cùng một đối tượng kết nối. Khi phạm vi nằm ngoài bố mẹ ban đầu, câu lệnh sử dụng sẽ đóng kết nối.

Đây là một mẫu mà tôi đã học được từ Rocky Lhotka trong khuôn khổ CSLA của mình.

Keith

+0

Cảm ơn Keith. Tôi thực sự thích cách tiếp cận của bạn - ConnectionManager là một lớp tốt đẹp giữa các kết nối và lệnh (bạn thậm chí có thể thực hiện tổng hợp của riêng bạn nếu bạn thực sự muốn). Tôi sẽ phải đọc chương này từ CSLA. –

+0

Tôi đang bối rối là tại sao bạn muốn có các thành viên quản lý đánh dấu ThreadStatic. Mỗi lần getter được truy cập từ một luồng mới, một bộ sưu tập người quản lý mới sẽ được tạo cho luồng đó đúng không? – dnewcome

+0

Tôi thấy lý do tại sao bạn sẽ muốn người quản lý riêng biệt cho mỗi luồng từ một quan điểm an toàn chủ đề. Bạn không muốn khả năng của một SqlConnection được truy cập bởi chủ đề khác hơn là tạo ra nó. Tôi không nghĩ nó sẽ là bất hợp pháp để làm như vậy, nhưng bạn thực sự mở cửa cho những điều bất ngờ. – dnewcome

1

ADO.NET Nhà cung cấp SQL Server tự kết nối tổng hợp. Bạn có thể kiểm soát kích thước hồ bơi theo số MinPoolSizeMaxPoolSize trong chuỗi kết nối.

1

Bạn thực sự không nên tự xử lý vấn đề này, vì có vô số công cụ ngoài đó có thể làm điều đó cho bạn.

Nếu bạn thực sự muốn tự mình làm, hãy xem mẫu Unit of Work nơi bạn có thể quản lý vòng đời kết nối/giao dịch. Bạn chắc chắn không muốn cố gắng điều hướng vùng nước lộn xộn nơi có các kết nối được mở ra/đóng cửa ở những nơi khác nhau.

Nếu bạn quyết định để các thành phần của bạn trực tiếp mở kết nối db thì có khả năng vòng đời kết nối sẽ quá chi tiết và dẫn đến nhiều kết nối mở/đóng cho một thao tác người dùng.

+0

chỉ để thêm ... một số công cụ sẽ bao gồm NHibernate, LINQ to SQL, SubSonic và các ... –

+0

Cảm ơn Ben Bạn hoàn toàn đúng rằng trong các trường hợp phổ biến, tùy chọn tốt nhất là sử dụng một số khuôn khổ kiên trì đối tượng . Thật không may là sản phẩm của công ty tôi không có nhiều đối tượng "cố định" nhưng thay vào đó nó cho phép người dùng tạo các bảng tùy chỉnh (như MS Access) - vì vậy tôi không thể thực sự sử dụng OPF. –

0

Một điều cần được cảnh giác trong ví dụ của bạn là ASP.NET ứng dụng không nên sử dụng lưu trữ ThreadStatic, như một sợi chỉ có thể được tái sử dụng, và nếu bạn không dọn dẹp tất cả các đối tượng của bạn, bạn kết thúc với một kết nối treo xung quanh.

Trong ứng dụng ASP.NET, tôi sử dụng bộ sưu tập HttpContext.Items để thay thế. Bạn đang thực hiện IDisposable, nhưng tôi đã nhìn thấy kịch bản mà devs quên gọi Dispose hoặc đặt mã trong một khối sử dụng.

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