Question

J'ai initialement conçu mon système en suivant l'exemple d'architecture s # décrit dans cet article CodeProject (Malheureusement, je n’utilise pas NHibernate). L'idée de base est que pour chaque objet de domaine devant communiquer avec la couche de persistance, vous avez un objet d'accès aux données correspondant dans une bibliothèque différente. Chaque objet d'accès aux données implémente une interface et lorsqu'un objet de domaine a besoin d'accéder à une méthode d'accès aux données, il code toujours contre une interface et jamais contre les DAO eux-mêmes.

À l’époque, et toujours, j’ai trouvé cette conception très flexible. Cependant, à mesure que la quantité d'objets dans mon modèle de domaine a augmenté, je me demande s'il n'y a pas de problème d'organisation ici. Par exemple, presque tous les objets du domaine se voient attribuer les interfaces Data Access Object et Data Access Object correspondantes. Non seulement cela, mais chacun d'entre eux se trouve à un endroit différent, ce qui est plus difficile à maintenir si je veux faire quelque chose de simple, comme déplacer certains espaces de noms.

Il est intéressant de noter que beaucoup de ces DAO (et leurs interfaces correspondantes) sont des créatures très simples - la plus courante n’a qu’une seule méthode GetById (). Je me retrouve avec tout un tas d'objets tels que

public interface ICustomerDao {
  Customer GetById(int id);
}

public interface IProductDao {
  Product GetById(int id);
}
public interface IAutomaticWeaselDao {
  AutomaticWeasel GetById(int id);
}

Là où leurs implémenteurs sont aussi très triviaux. Je me suis demandé s'il ne serait pas plus simple d'aller dans une direction différente, peut-être changer de stratégie en n'utilisant qu'un seul objet pour de simples tâches d'accès aux données et en réservant la création d'objets dédiés d'accès aux données à ceux qui ont besoin de quelque chose de plus. compliqué.

public interface SimpleObjectRepository {
      Customer GetCustomerById(int id);
      Product GetProductById(int id);
      AutomaticWeasel GetAutomaticWeaselById(int id);
      Transaction GetTransactioinById(int id);
}
public interface TransactionDao {
  Transaction[] GetAllCurrentlyOngoingTransactionsInitiatedByASweatyGuyNamedCarl();
}

Quelqu'un at-il une expérience avec une telle architecture? Globalement, je suis très satisfait de la configuration car ma seule préoccupation est maintenant la gestion de tous ces petits fichiers. Je me demande toutefois quelles sont les autres approches possibles pour structurer la couche d'accès aux données.

Était-ce utile?

La solution

Je recommande contre l'approche simple autre que dans les systèmes simples, je pense généralement qu'il vaut mieux créer un référentiel personnalisé pour chaque agrégat et encapsuler autant de logique que possible dans celui-ci.

Mon approche consisterait donc à créer un référentiel pour chaque agrégat qui en a besoin, tel que CustomerRepository. Cela aurait une méthode Add (enregistrer) et, si approprié pour cet agrégat, une méthode Remove (delete). Toutes les autres méthodes personnalisées, y compris les requêtes (GetActive), pourraient être acceptées et certaines de ces requêtes pourraient peut-être accepter des spécifications.

Cela ressemble à beaucoup d’effort, mais à part les requêtes personnalisées, la plupart du code est, du moins si vous utilisez un ORM moderne, très simple à implémenter, j’utilise donc l’héritage (ReadWriteRepositoryBase où T: IAggregateRoot) et / ou composition (appel à une classe RepositoryHelper). La classe de base peut avoir des méthodes qui s'appliquent dans tous les cas, tels que GetById.

J'espère que cela vous aidera.

Autres conseils

Je travaille en PHP, mais j'ai une configuration similaire pour ma couche d'accès aux données. J'ai implémenté une interface qui ressemble à ceci:

interface DataAccessObject
{
public static function get(array $filters = array(), array $order = array(), array $limit = array());
public function insert();
public function update();   
public function delete();
}

Ensuite, chacun de mes objets d'accès aux données fonctionne de la manière suivante:

class DataAccessObject implements DataAccessObject
{
    public function __construct($dao_id = null) // So you can construct an empty object
    {
        // Some Code that get the values from the database and assigns them as properties
    }
    public static function get(array $filters = array(), array $order = array(), array $limit = array()) {};  // Code to implement function
    public function insert() {};  // Code to implement function
    public function update() {};  // Code to implement function 
    public function delete() {};  // Code to implement function        
}

Je suis en train de construire manuellement chacune des classes d'objet d'accès aux données. Ainsi, lorsque j'ajoute une table ou que je modifie une table existante dans la base de données, il est évident que je dois écrire le nouveau code à la main. Dans mon cas, cela représente toujours un progrès considérable par rapport à notre base de code.

Cependant, vous pouvez également utiliser les métadonnées SQL (en supposant que vous disposez d'une conception de base de données assez solide qui tire parti des contraintes de clé étrangère, etc.) pour générer ces objets d'accès aux données. Ensuite, en théorie, vous pourriez utiliser une seule classe DataAccessObject parente pour construire les propriétés et les méthodes de la classe et même pour établir automatiquement des relations avec les autres tables de la base de données. Cela correspondrait plus ou moins à la même chose que ce que vous décrivez car vous pourriez alors étendre la classe DataAccessObject pour fournir des méthodes et des propriétés personnalisées aux situations nécessitant une certaine quantité de code construit manuellement.

En tant que note de bas de page pour le développement .NET, avez-vous examiné un framework qui gère pour vous la structure sous-jacente de la couche d'accès aux données, telle que Subsonic? Sinon, je vous conseillerais de vous pencher sur un tel cadre: http://subsonicproject.com/ .

Pour le développement PHP, un framework tel que Zend Framework fournirait des fonctionnalités similaires: http://framework.zend.com

George, je sais exactement ce que tu ressens. L'architecture de Billy me semble logique, mais la nécessité de créer un conteneur, les fichiers Imapper et Mapper est pénible. Ensuite, si vous utilisez NHibernate, le fichier .hbm corrosponding et généralement quelques scripts de test unitaire permettant de tout vérifier.

Je suppose que même si vous n'utilisez pas NHibernate, vous utilisez toujours une classe de base générique pour charger / enregistrer vos conteneurs, c.-à-d.

public class BaseDAO<T> : IDAO<T> 
{
     public T Save(T entity)
     { 
       //etc......
     }
}
public class YourDAO : BaseDAO<YourEntity>
{
}

Je suppose que sans NHibernate, vous utiliseriez une réflexion ou un autre machanisme pour déterminer quel SQL / SPROC appeler?

Dans tous les cas, je pensais que DAO ne devrait exécuter que les opérations CRUD de base définies dans la classe de base, il ne devrait donc pas être nécessaire d’écrire des mappeurs et des interfaces personnalisés. La seule façon pour moi d’y parvenir consiste à utiliser Reflection.Emit pour créer dynamiquement votre DAO à la volée.

J'utilise également le modèle de référentiel pour mon DAO et je suis très heureux avec ça. Oui, vous vous retrouvez avec quelques petites classes, mais c'est très facile à maintenir. C'est un peu plus puissant si vous utilisez l'interface IQueriable (LINQ.). Vous pouvez également utiliser des génériques (quelque chose comme T GetById<T>(int id)) si vous avez une structure de base de données assez cohérente.

Le deuxième inconvénient de la deuxième approche réside dans les tests unitaires: se moquer de méthodes d'usine telles que SimpleObjectRepository nécessite plus de travail que de se moquer d'ICustomerDao. Mais mon projet va avec la deuxième approche pour les objets très liés (où la plupart seront utilisés dans tous les tests unitaires) car elle allège la charge mentale et la rend plus facile à gérer.

Je découvrirais ce qui rend votre système plus facile à gérer, à gérer et à comprendre.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top