web-dev-qa-db-fra.com

Modèle DAO vs ORM (hibernation)

j'ai lu dans certains articles que DAO n'est pas obligatoire avec hibernate et sa mise en œuvre se fait par "ça dépend", en d'autres termes, on peut choisir entre ORM vs motif DAO.

Ok, supposons que je ne veux pas utiliser de modèle DAO, donc je n'utilise que la session CRUD et l'opération de requête fournie par hibernate (mon ORM).

Surtout pour les requêtes "rechercher" et "trouver" il n'est pas correct de toujours les réécrire, il est donc raisonnable de penser à les mettre dans une classe.

Mais alors cette classe est un DAO simple sans toute implémentation du modèle DAO et DAOFactory, seulement une implémentation légère d'un DAO. Donc, le fait est que nous avons toujours besoin d'un DAO et le choix est une implémentation DAO lourde vs une implémentation DAO légère?

Ce que j'ai dit est faux?

EDIT Un autre problème que j'ai est de savoir où mettre les interactions dao, par exemple je dois connecter un utilisateur et écrire un journal de connexion (exemple inutile je sais .. .)

Donc, dans un modèle DAO, j'ai toutes les implémentations dao génériques, une DAOFactory et enfin UserHibernateDAO et LogHibernateDAO. L'opération de connexion est une méthode commerciale:

private void login(String username, String password){
    daoFactory.beginTransaction();
    UserDAO userDao=daoFactory.HIBERNATE.getUserDao();
    LogDAO logDao=daoFactory.HIBERNATE.getLogDao();
    if(userDao.checkAccount(username, password){
        User user=userDao.findByAccount(username, password);
        logDao.save(new Log("log-in", user);
    }
    daoFactory.commit();
}

Est-ce raisonnable? Puis-je utiliser dao de cette manière? Si je veux gérer l'exception, le meilleur endroit pour le faire est dans une logique métier?

EDIT2 Supposons d'utiliser un modèle DAO, la principale raison de le faire est de pouvoir basculer entre la technologie (ORM-> JDBC etc.), tout va bien et ok, MAIS où puis-je gérer la session et la transaction de mise en veille prolongée? Je ne peux pas le mettre dans un DAO, c'est un modèle anty, et je ne peux pas le mettre dans une couche de service, car dans un commutateur hipohtetycal, je dois supprimer toute cette transaction (car d'autres technologies peuvent ne pas les utiliser).

45
blow

ORM et DAO sont des concepts orthogonaux. L'une concerne la façon dont les objets sont mappés aux tables de base de données, l'autre est un modèle de conception pour écrire des objets qui accèdent aux données. Vous ne choisissez pas entre eux. Vous pouvez avoir ORM et DAO est la même application, tout comme vous n'avez pas besoin d'ORM pour utiliser le modèle DAO.

Cela dit, bien que vous n'ayez jamais vraiment besoin quoi que ce soit, vous devez utiliser les DAO. Le modèle se prête au code modularisé. Vous conservez toute votre logique de persistance en un seul endroit (séparation des préoccupations, lutte contre les abstractions qui fuient). Vous vous autorisez à tester l'accès aux données séparément du reste de l'application. Et vous vous autorisez à tester le reste de l'application isolée de l'accès aux données (c'est-à-dire que vous pouvez vous moquer de vos DAO).

De plus, suivre le modèle DAO est facile, même si la mise en œuvre de l'accès aux données peut être difficile. Cela vous coûte donc très peu (ou rien) et vous gagnez beaucoup.

EDIT - En ce qui concerne votre exemple, votre méthode de connexion doit être dans une sorte de AuthenticationService. Vous pouvez y gérer des exceptions (dans la méthode de connexion). Si vous utilisiez Spring, il pourrait gérer un tas de choses pour vous: (1) transactions, (2) injection de dépendance. Vous n'auriez pas besoin d'écrire vos propres transactions ou usines dao, vous pourriez simplement définir des limites de transaction autour de vos méthodes de service, définir vos implémentations DAO en tant que beans, puis les connecter à votre service.

EDIT2

La principale raison d'utiliser le modèle est de séparer les préoccupations. Cela signifie que tout votre code de persistance est au même endroit. Un effet secondaire de ceci est la capacité de test et la maintenabilité, et le fait que cela facilite le changement d'implémentations plus tard. Si vous créez des DAO basés sur Hibernate, vous pouvez absolument manipuler la session dans le DAO, c'est ce que vous êtes censé faire. L'anti modèle se produit lorsque le code lié à la persistance se produit en dehors de la couche de persistance (loi des abstractions qui fuient).

Les transactions sont un peu plus délicates. À première vue, les transactions peuvent sembler être une préoccupation de persistance, et elles le sont. Mais ils ne sont pas seulement un souci de persévérance. Les transactions sont également une préoccupation pour vos services, dans la mesure où vos méthodes de service doivent définir une "unité de travail", ce qui signifie que tout ce qui se passe dans une méthode de service doit être atomique. Si vous utilisez des transactions de mise en veille prolongée, vous devrez écrire le code de transaction de mise en veille prolongée en dehors de vos DAO, pour définir les limites des transactions autour des services qui utilisent de nombreuses méthodes DAO.

Mais notez que les transactions peuvent être indépendantes de votre implémentation - vous avez besoin de transactions que vous utilisiez ou non hibernate. Notez également que vous n'avez pas besoin d'utiliser le mécanisme de transaction hibernate - vous pouvez utiliser des transactions basées sur des conteneurs, des transactions JTA, etc.

Nul doute que si vous n'utilisez pas Spring ou quelque chose de similaire, les transactions vont être pénibles. Je recommande fortement d'utiliser Spring pour gérer vos transactions, ou la spécification EJB où je - croyez vous pouvez définir des transactions autour de vos services avec des annotations.

Consultez les liens suivants pour les transactions basées sur des conteneurs.

Transactions gérées par conteneur

Sessions et transactions

Ce que j'en déduis, c'est que vous pouvez facilement définir les transactions en dehors des DAO au niveau du service, et vous n'avez pas besoin d'écrire de code de transaction.

Une autre alternative (moins élégante) consiste à placer toutes les unités atomiques de travail dans les DAO. Vous pouvez avoir des DAO CRUD pour les opérations simples, puis des DAO plus compliqués qui effectuent plusieurs opérations CRUD. De cette façon, vos transactions programmatiques restent dans le DAO, et vos services appelleraient les DAO les plus compliqués, et n'auraient pas à se soucier des transactions.

Le lien suivant est un bon exemple de la façon dont le modèle DAO peut vous aider à simplifier le code

modèle AO vs ORM (hibernation)

(merci @ daff )

Remarquez comment la définition de l'interface fait en sorte que votre logique métier ne se soucie que du comportement de UserDao. Il ne se soucie pas de la mise en œuvre. Vous pouvez écrire un DAO en utilisant hibernate, ou simplement JDBC. Vous pouvez donc modifier votre implémentation d'accès aux données sans affecter le reste de votre programme.

75
hvgotcodes

Permettez-moi de fournir un exemple de code source à hvgotcodes bonne réponse:

public class Application
{
    private UserDao userDao;

    public Application(UserDao dao)
    {
        // Get the actual implementation
        // e.g. through dependency injection
        this.userDao = dao;
    }

    public void login()
    {
        // No matter from where
        User = userDao.findByUsername("Dummy");
    }
}


public interface UserDao
{
    User findByUsername(String name);
}

public class HibernateUserDao implements UserDao
{
    public User findByUsername(String name)
    {
        // Do some Hibernate specific stuff
        this.session.createQuery...
    }
}

public class SqlUserDao implements UserDao
{
    public User findByUsername(String name)
    {
        String query = "SELECT * FROM users WHERE name = '" + name + "'";
        // Execute SQL query and do mapping to the object
    }
}

public class LdapUserDao implements UserDao
{
    public User findByUsername(String name)
    {
        // Get this from LDAP directory
    }
}

public class NoSqlUserDao implements UserDao
{
    public User findByUsername(String name)
    {
        // Do something with e.g. couchdb
        ViewResults resultAdHoc = db.adhoc("function (doc) { if (doc.name=='" + name + "') { return doc; }}");
        // Map the result document to user
    }
}

Ainsi, comme déjà mentionné, DAO est un modèle de conception pour minimiser le couplage entre votre application et votre backend tandis que ORM traite de la façon de mapper des objets dans une base de données relationnelle objet (ce qui réduit le couplage entre la base de données et votre application, mais à la fin, sans utiliser un DAO, votre application dépendrait de l'ORM utilisé ou à un niveau supérieur d'une norme comme JPA).

Par conséquent, sans DAO, il serait très difficile de changer votre application (par exemple, passer à une base de données NoSQL au lieu d'un ORM compatible JPA).

30
Daff

Non, je ne pense pas que ce soit correct. ORM est une façon d'implémenter DAO; vous pouvez choisir de faire DAO sans ORM.

Vous l'avez à l'envers: je considérerais ORM plus lourd que DAO, car les dépendances sont plus importantes. Je peux écrire un DAO en JDBC droit sans ORM. C'est plus léger, OMI.

Que nous soyons d'accord ou non dépend de la façon dont nous définissons "léger" et "lourd". Je vais par dépendances - le nombre de JAR supplémentaires requis au-dessus du JDK lui-même.

12
duffymo