Wie soll ich den Datenbankzugriff kapseln?

10

Was sind einige Beispiele für gute Klassenstrukturen, die zum Verwalten des Datenbankzugriffs verwendet werden? Ich bin ein Fan der Klassenkapselung und würde es vorziehen, wenn die Container (z. B. das Auto) keine Datenbankaufgaben ausführen.

Ich möchte auch die Möglichkeit haben, in Zukunft problemlos Dinge wie einen Datenbank-Cache abzulegen.

Ich nehme oft das Muster von Containerklassen, einschließlich Getter und Setter für die Validierung und den Datenbankzugriff, die von einer einzelnen Singleton-Klasse ausgeführt werden. Davon abgesehen wird dies oft zwischen den beiden gemischt und wird ziemlich verwirrend.

Entschuldigung, wenn meine Frage schwer zu verstehen ist; Bei den Datenbanken bin ich mir nicht ganz sicher. Bitte fragen Sie bei Bedarf nach einer Klärung.

Will03uk
quelle
Haben Sie darüber nachgedacht, ein ORM zu verwenden, um Klassen mit Datenbanken wie Wt :: Dbo zu verknüpfen ?
user52875

Antworten:

11

Ich bevorzuge das Repository-Muster , um den Datenzugriff zu kapseln. Kurz gesagt, das Repository ist dafür verantwortlich, alle für ein bestimmtes Objekt erforderlichen Daten zu laden. Angenommen, Sie haben ein Autoobjekt, wie in Ihrem Beispiel. Alle Attribute für Auto, Marke, Modell, Jahr, Besitzer, Funktionen (CD-Player, Allrad usw.) werden jedoch in verschiedenen Tabellen in der gesamten Datenbank gespeichert. Das Repository bestimmt, wie die Daten geladen und gespeichert werden. Wenn mehrere kleinere Abfragen erforderlich sind, ist dies in Ordnung, aber nur das Repository-Muster muss dies wissen. Die Service-Schicht, die das Repository aufruft, muss nur wissen, welches Repository aufgerufen werden soll.

Das kann dann mit der Arbeitseinheit kombiniert werden . In Ihrem Beispiel würde die Serviceschicht also sagen, dass sie eine Fahrzeugentität laden muss, eine eindeutige Kennung hat und diese Kennung an das Repository sendet. Das Repository gibt die Fahrzeugentität zurück. Ein anderer Code manipuliert die Fahrzeugentität und sendet diese Entität an das Repository zurück, damit sie gespeichert werden kann.

Wenn Sie wirklich alles daran setzen möchten, würde die Repository-Schicht nur Schnittstellen wie ICarRepository verfügbar machen. Das Repository würde eine Factory enthalten , die die Service-Schicht verwenden würde, um die ICarRepository-Schnittstelle abzurufen. Der gesamte Datenbankzugriff würde hinter einer Schnittstelle verborgen sein, was das Testen von Einheiten erheblich vereinfacht.

bwalk2895
quelle
Alles schön, bis auf das letzte bisschen über Schnittstellen, die in C ++ nicht existieren (es sei denn, das OP wollte C ++ nicht markieren). Ich bin sehr gespannt auf eine Repository-Pattern-Implementierung in C ++, da ich sie mit QT verwenden möchte. Ich bin erstaunt, dass online nichts brauchbar ist = [
johnildergleidisson
6

Ich habe das Strategiemuster verwendet , um den Datenzugriff zu kapseln. Mit diesem Muster können Sie den Speichertyp, den Sie verwenden, hinter einer gemeinsamen Schnittstelle verbergen. Definieren Sie in der Benutzeroberfläche Ihre Datenzugriffsmethoden unter Berücksichtigung der Art des Speichers (Datei, Datenbank, Web). Implementieren Sie dann für Ihre aktuelle Speicherauswahl in einer Klasse, die die Strategie-Schnittstelle realisiert, die Datenzugriffsdetails. Auf diese Weise kümmert sich Ihre Anwendung nicht um die von Ihnen verwendete Datenquelle.

Sie können auch eine Service-Schicht erstellen, die die aktuelle Instanz der Datenspeicherungsstrategie verwendet, um anwendungsspezifische Details zu definieren, anstatt Datenzugriff und Geschäftslogik miteinander zu mischen.

Mike L.
quelle
Würden Sie also für jeden Typ eine Zugriffsklasse oder für alle eine große Klasse hinzufügen?
Will03uk
persönlich würde ich auch die Übernahme expliziter Castings für alle Daten in Betracht ziehen, die von der Wildnis auf meinen Server / meine Anwendung eingehen.
user827992
+1 Ich mag das Aussehen dieses Musters, aber ich bin der Meinung, dass es (auf der Skala meines Projekts) schwierig sein wird, jeden Algorithmus für eine Datenbank separat zu verwalten. obwohl ich dies sicherlich in anderen Anwendungen verwenden werde. Lambdas müssen dies gut ergänzen.
Will03uk
1

Dies ist ein Beispiel für das Factory-Muster der Datenbank.

using System.Reflection;
using System.Configuration;

public sealed class DatabaseFactory
{
    public static DatabaseFactorySectionHandler sectionHandler = (DatabaseFactorySectionHandler)ConfigurationManager.GetSection("DatabaseFactoryConfiguration");

    private DatabaseFactory() { }

    public static Database CreateDatabase()
    {
        // Verify a DatabaseFactoryConfiguration line exists in the web.config.
        if (sectionHandler.Name.Length == 0)
        {
            throw new Exception("Database name not defined in DatabaseFactoryConfiguration section of web.config.");
        }

        try
        {
            // Find the class
            Type database = Type.GetType(sectionHandler.Name);

            // Get it's constructor
            ConstructorInfo constructor = database.GetConstructor(new Type[] { });

            // Invoke it's constructor, which returns an instance.
            Database createdObject = (Database)constructor.Invoke(null);

            // Initialize the connection string property for the database.
            createdObject.connectionString = sectionHandler.ConnectionString;

            // Pass back the instance as a Database
            return createdObject;
        }
        catch (Exception excep)
        {
            throw new Exception("Error instantiating database " + sectionHandler.Name + ". " + excep.Message);
        }
    }
}
theclai
quelle