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
Nguồn
2009-01-05 20:07:42
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. –
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
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