Ich musste ein Verbindungsobjekt weitergeben, damit ich mehreren Geschäftsobjekten erlauben konnte, sich innerhalb einer einzigen Transaktion in der Datenbank zu speichern.
Wenn jedes Geschäftsobjekt eine eigene SQLConnection für die Datenbank erstellen musste, würde die Transaktion zu einer verteilten Transaktion eskalieren, und das wollte ich vermeiden.
Ich wollte das SQLConnection-Objekt nicht als Parameter übergeben, um ein Objekt zu speichern. Daher habe ich einen ConnectionManager erstellt, der das SQLConnection-Objekt für mich erstellt, die Verwendung des SQLConnection-Objekts verfolgt und das SQLConnection-Objekt trennt Nicht in Gebrauch.
Hier ist ein Code als ein Beispiel für die 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
}
Hier ist, wie ich es von einem Business-Objekt verwenden würde:
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.
}
}
ich ein Business-Objekt und alle seine sparen Kinder werden ebenfalls mit demselben Verbindungsobjekt gespeichert. Wenn der Bereich vom ursprünglichen übergeordneten Element entfernt wird, schließt die using-Anweisung die Verbindung.
Dies ist ein Muster, das ich von Rocky Lhotka in seinem CSLA-Framework gelernt habe.
Keith
Danke Keith. Ich mag Ihren Ansatz wirklich - ConnectionManager ist eine nette Schicht zwischen Verbindungen und Befehlen (Sie können sogar Ihr eigenes Pooling implementieren, wenn Sie wirklich wollen). Ich werde dieses Kapitel von CSLA lesen müssen. –
Ich bin verwirrt, warum Sie möchten, dass das Manager-Mitglied ThreadStatic markiert. Jedes Mal, wenn auf den Getter von einem neuen Thread zugegriffen wird, wird eine neue Manager-Sammlung für diesen Thread erstellt, richtig? – dnewcome
Ich sehe, warum Sie separate Manager für jeden Thread vom Standpunkt der Threadsicherheit wünschen. Sie möchten nicht, dass auf eine SqlConnection von einem anderen Thread als dem, der sie erstellt hat, zugegriffen werden kann. Ich denke nicht, dass es illegal wäre, aber du öffnest wirklich die Tür für unerwartete Dinge. – dnewcome