29 votes

Pourquoi placer une couche DAO au-dessus d'une couche de persistance (comme JDO ou Hibernate) ?

Les objets d'accès aux données (DAO) sont un modèle de conception commun, et sont recommandés par Sun. Mais les premiers exemples de DAO Java interagissaient directement avec les bases de données relationnelles - ils faisaient, en fait, du mapping objet-relationnel (ORM). Aujourd'hui, je vois des DAO au-dessus de cadres ORM matures comme JDO et Hibernate, et je me demande si c'est vraiment une bonne idée.

Je suis en train de développer un service web utilisant JDO comme couche de persistance, et je me demande s'il faut ou non introduire des DAO. Je prévois un problème lorsqu'il s'agit d'une classe particulière qui contient une carte d'autres objets :

public class Book {
    // Book description in various languages, indexed by ISO language codes
    private Map<String,BookDescription> descriptions;
}

JDO est suffisamment intelligent pour faire correspondre cela à une contrainte de clé étrangère entre les tables "BOOKS" et "BOOKDESCRIPTIONS". Il charge de manière transparente les objets BookDescription (en utilisant le chargement paresseux, je crois), et les persiste lorsque l'objet Book est persistant.

Si je devais introduire une "couche d'accès aux données", écrire une classe comme BookDao et y encapsuler tout le code JDO, le chargement transparent des objets enfants par JDO ne contournerait-il pas la couche d'accès aux données ? Par souci de cohérence, tous les objets BookDescription ne devraient-ils pas être chargés et persistés via un objet BookDescriptionDao (ou la méthode BookDao.loadDescription) ? Pourtant, un tel remaniement compliquerait inutilement la manipulation du modèle.

Ma question est donc la suivante : qu'y a-t-il de mal à appeler JDO (ou Hibernate, ou tout autre ORM de votre choix) directement dans la couche métier ? Sa syntaxe est déjà assez concise, et il est indépendant du datastore. Quel est l'avantage, le cas échéant, de l'encapsuler dans des objets d'accès aux données ?

11voto

KLE Points 11711

Vous marquez des points. Mais j'utilise néanmoins une couche de Dao, voici pourquoi :

  1. Les accès aux bases de données sont appels vers un système distant . Dans tous ces cas (également les services web, ajax etc...), la granularité de l'interaction doit être suffisamment grande. De nombreux petits appels tueraient les performances. Cette nécessité de performance requiert souvent une vue différente du système, ou de la couche (ici, la couche Dao).

  2. Parfois, votre opération de persistance consiste uniquement à charger/enregistrer/supprimer un objet. Un seul Dao (ou une superclasse ; pensez aux génériques) peut être responsable de cette opération, ce qui vous évite de devoir coder ces méthodes encore et encore.
    Mais souvent, vous avez aussi des besoins spécifiques, comme l'exécution d'une requête spécifique qui n'est pas automatiquement créée par l'ORM . Là, vous codez votre besoin spécifique avec une méthode Dao spécifique (la réutilisation est souvent possible).
    Le fait d'avoir des besoins réguliers et spécifiques dans la même couche permet de les réutiliser (par exemple, l'interception peut garantir qu'une connexion à une base de données est ouverte/commandée lorsque cela est nécessaire).

10voto

7SpecialGems Points 1950

La DAO a perdu son sens au fil du temps.

À l'époque de J2EE, lorsqu'il est devenu un modèle populaire, un DAO était une classe permettant de prendre en charge simultanément plusieurs sources de données - une base de données d'un fournisseur, une base de données d'un autre fournisseur, un fichier - et de fournir un endroit unique pour envelopper les requêtes afin de communiquer pour les données.

Il y avait beaucoup de possibilités de réutilisation, de sorte qu'un objet DAO pour une entité particulière pouvait très bien étendre un DAO abstrait qui abritait le matériel réutilisable, qui lui-même implémentait une interface DAO.

Après J2EE/EJB, les modèles DataMapper et DataSource (ou pour les systèmes simples, ActiveRecord) sont devenus populaires pour remplir le même rôle. Cependant, DAO est devenu un mot à la mode pour tout objet impliqué dans la persistance.

Aujourd'hui, le terme "DAO" est malheureusement devenu un synonyme de "classe qui me permet de communiquer avec ma base de données".

Avec ORM / JPA, une grande partie de la logique d'un véritable DAO de l'ère J2EE est fournie d'emblée.

Dans le cas d'un dernier modèle DataSource, l'EntityManager de JPA est semblable à la DataSource, mais il est généralement fourni via une définition XML de PersistenceUnit et instancié via IoC.

Les méthodes CRUD qui se trouvaient auparavant dans un DAO ou un Mapper peuvent maintenant être fournies exactement une fois en utilisant le modèle de référentiel. Il n'y a pas besoin d'AbstractDAO - les produits ORM sont suffisamment intelligents pour accepter un Object() et savoir où le persister.

9voto

Preet Sangha Points 39414

Cela dépend des objectifs de votre couche. Vous mettez une abstraction pour fournir un ensemble différent de sémantique sur un autre ensemble. En général, les couches supplémentaires sont là pour simplifier certaines choses comme le développement de la maintenance future. Mais elles peuvent avoir d'autres usages.

Par exemple, une couche DAO (ou de gestion de la persistance) au-dessus d'un code ORM fournit une fonctionnalité spécialisée de récupération et de gestion des erreurs que vous ne souhaitez pas voir polluer la logique métier.

5voto

skaffman Points 197885

Un seul mot: transactions

Prenons la situation où je dois effectuer deux opérations de mise à jour en une seule transaction. Ces opérations forment ensemble une unité logique de travail. Mon entreprise, la logique veut s'exprimer en termes de l'unité de travail, et il ne veut pas s'embêter avec des limites des transactions.

Alors, j'ai écrit un DAO. Prendre ce pseudo-code à l'aide de Printemps des opérations et de la mise en veille prolongée:

édité pour supprimer les requêtes HQL qui était fautif @Roger tellement, mais qui n'était pas pertinente du point de

@Transactional
public void doUnitOfWork() {
  // some persistence operation here
  // some other persistence operation here
}

Ma logique métier appels doUnitOfWork(), qui commence une transaction, effectue les opérations de persistance, et puis valide. Il ne sait ni se soucie de la transaction, ou ce que les opérations sont effectuées.

En outre, si le DAO implémente une interface avec le doUnitOfWork() la méthode, alors la logique métier peut code de l'interface, ce qui rend plus facile de test de l'unité.

En général, j'ai toujours emballer mes opérations d'accès aux données dans un DAO, et whack une interface autour d'elle.

4voto

Rogério Points 5460

Lorsqu'on utilise un outil ORM comme JDO ou JPA, les DAO sont un anti-modèle. Dans ce cas, la création d'une "couche d'accès aux données" est totalement inutile et ne fera qu'ajouter du code supplémentaire et de la complexité à la base de code, la rendant plus difficile à développer et à maintenir.

Sur la base de mon expérience précédente, je recommanderais l'utilisation d'une simple façade statique, par exemple Persistence Le but est de fournir une API de haut niveau, facile à utiliser, pour les opérations liées à la persistance.

Ensuite, vous pouvez utiliser une importation statique pour obtenir un accès facile à ces méthodes partout où elles sont utiles. Par exemple, vous pourriez avoir un code comme le suivant :

    List<Book> cheapBooks = 
        find("select b from Book where b.price < ?", lowPriceForBooks);
    ...
    Book b = new Book(...);
    persist(b);
    ...
    Book existingBook = load(Book.class, bookId);
    remove(existingBook);
    ...

Le code ci-dessus est aussi simple et facile que possible, et peut être facilement testé à l'unité.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X