Comment dois-je encapsuler l'accès à la base de données?

10

Quels sont quelques exemples de bonnes structures de classe utilisées pour gérer l'accès à la base de données? Je suis un fan de l'encapsulation de classe et je préférerais que les conteneurs (par exemple la voiture) n'effectuent pas de tâches de base de données.

J'aimerais également pouvoir déposer facilement des éléments comme un cache de base de données à l'avenir.

Je prends souvent le modèle des classes de conteneur, avec des getters et setters pour la validation et l'accès à la base de données effectués par une seule classe singleton. Cela étant dit, cela se mélange souvent entre les deux et devient assez déroutant.

Désolé si ma question est difficile à comprendre; Je ne suis pas absolument sûr des conditions concernant les bases de données. N'hésitez pas à demander des éclaircissements si nécessaire.

Will03uk
la source
Avez-vous envisagé d'utiliser un ORM pour lier des classes à des bases de données, telles que Wt :: Dbo ?
user52875

Réponses:

11

Je préfère le modèle de référentiel pour encapsuler l'accès aux données. En bref, le référentiel est responsable du chargement de toutes les données requises pour un objet spécifique. Disons que vous avez un objet Car, comme dans votre exemple. Mais tous les attributs de la voiture, de la marque, du modèle, de l'année, des propriétaires, des fonctionnalités (lecteur CD, 4x4, etc.) sont stockés dans diverses tables de la base de données. Le référentiel détermine comment charger et enregistrer les données. Si plusieurs requêtes plus petites sont nécessaires, très bien, mais seul le modèle de référentiel doit le savoir. La couche de service appelant le référentiel n'a besoin que de savoir quel référentiel appeler.

Cela peut ensuite être combiné avec l' unité de travail . Ainsi, dans votre exemple, la couche de service dirait qu'elle doit charger une entité de voiture, elle a une sorte d'identifiant unique et envoie cet identifiant vers le référentiel. Le référentiel renvoie l'entité car. Un autre code manipule l'entité car et renvoie cette entité au référentiel afin qu'elle puisse être enregistrée.

Si vous voulez vraiment tout mettre en œuvre, la couche de référentiel exposerait uniquement les interfaces, telles que ICarRepository. Le référentiel contiendrait une fabrique que la couche de service utiliserait pour obtenir l'interface ICarRepository. Tout accès à la base de données serait caché derrière une interface, ce qui rend les tests unitaires beaucoup plus faciles.

bwalk2895
la source
Tout est bien sauf le dernier bit sur les interfaces qui en c ++ n'existent pas (sauf si l'OP ne voulait pas marquer c ++). Je suis très curieux de voir une implémentation de modèle de référentiel en C ++ car je veux l'utiliser avec QT. Je suis étonné qu'il n'y ait rien utilisable en ligne = [
johnildergleidisson
6

J'ai utilisé le modèle de stratégie pour encapsuler l'accès aux données. Ce modèle vous permet de masquer le type de stockage que vous utilisez derrière une interface commune. Dans l'interface, définissez vos méthodes d'accès aux données sans tenir compte du type de stockage (fichier, base de données, web). Ensuite, pour votre choix de stockage actuel, dans une classe réalisant l'interface de stratégie, implémentez les détails d'accès aux données. De cette façon, votre application ne se soucie pas de la source de données que vous utilisez.

Vous pouvez également créer une couche de service qui utilise l'instance de stratégie de stockage de données actuelle pour définir des détails plus spécifiques à l'application au lieu de mélanger l'accès aux données et la logique métier.

Mike L.
la source
Alors, ajouteriez-vous une classe d'accès pour chaque type ou une grande classe pour tous?
Will03uk
personnellement, j'envisagerais également l'adoption de castings explicites pour toutes les données provenant de la nature sur mon serveur / application.
user827992
+1 J'aime l'aspect de ce modèle, mais je pense (à l'échelle de mon projet), gérer chaque algorithme séparément pour une base de données sera difficile; même si je vais certainement l'utiliser dans d'autres applications. Les lambdas doivent bien compléter cela.
Will03uk
1

Ceci est un exemple de modèle Factory de base de données;

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
la source