Я обнаружил, что мне нужно обойти объект соединения, чтобы я мог позволить нескольким бизнес-объектам сохранять себя в базе данных в рамках одной транзакции.
Если бы каждый бизнес-объект должен был создать свою собственную связь SQLC с базой данных, транзакция переросла бы в распределенную транзакцию, и я хотел бы избежать этого.
Мне не нравилось передавать объект SQLConnection в качестве параметра для сохранения объекта, поэтому я создал ConnectionManager, который обрабатывает создание объекта SQLConnection для меня, отслеживая использование объекта SQLConnection и отключая объект SQLConnection, когда это не так. используется.
Вот пример кода для 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
}
Вот как бы я использовал это из бизнес-объекта:
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.
}
}
Я сохраняю бизнес-объект, и все его дочерние объекты также сохраняются с использованием одного и того же объекта подключения. Когда область действия выходит за пределы исходного родительского объекта, оператор using закрывает соединение.
Это паттерн, который я выучил у Роки Лхотки в его рамках CSLA.
Keith