Acesso ao EntityManager: através de um DAO ou diretamente?

Oi pessoal

Estou escrevendo sobre persistência, e cai na polêmica parte de DAO, Mappers, EntityManager e patterns.

Essa é uma antiga discussão. Devo usar DAO se estou em um ambiente com EJB+JPA?

O Adam Bien té da opiniao que nao devemos mais usar o DAO, e acessar o EntityManager diretamente (em especial se só for um wrapper):
http://www.adam-bien.com/roller/abien/entry/jpa_ejb3_killed_the_dao

Obviamente isso pode gerar confusoes e muita gente fazendo os mesmos procedimento, processando as mesmas entidades de certa forma que uma query nao permitiu buscar, etc. Tanto que ele da um passo pra trás e diz que você pode sim ter um DAO:
http://www.adam-bien.com/roller/abien/entry/you_should_dao_if

Os posts do Vincent Partington (muito bem escritos) ganharam muita popularidade esse ano, e vão para o outro lado, apoiando o uso do DAO (assim como outros):
http://blog.xebia.com/2009/03/09/jpa-implementation-patterns-data-access-objects/

(uma observação, o Vincent ainda aborda outros dois tópicos que eu concordo com ele: tomar cuidado com relacionamento bidirecional de entidades, e que o DTO não está morto, pode ser usado para ajustar granularidade (apenas quando necessário, claro)).

Curioso que essa discussão reaparece inúmeras vezes, e se você for ver, a galera do Spring tem uma opinião, a galera do Hibernate outra, do Glassfish outra, e assim por diante.

Sei que muitos tem preferências (eu também tenho) mas eu gostaria links e referências que deem base para a escolha. Qual é a sua preferência?

Eu acredito que existam “forças” que levam ao incentivo ou à rejeição do DAO.

As que rejeitam o uso do DAO acontece quando:

:arrow: Boa parte da funcionalidade do programa se resume a CRUD. Afinal, não há o que esconder, o negócio é o acesso ao banco.
:arrow: A funcionalidade é chamada genericamente de “relatório”.

As que incentivam o uso de DAO acontece quando:

:arrow: o banco é legado e não reflete a maneira como se pensa o negócio.
:arrow: a entidade persistida possui vários estados onde, em alguns deles, não se permite a inserção/alteração/remoção. O DAO pode impedir operações de maneira consistente.
:arrow: o negócio é complexo, exigindo separar qualquer coisa que impeça uma visão em alto nível.

De qualquer maneira, o JPA sempre vazará a transação, o que significa que só ela é incapaz de encapsular o acesso aos dados. Também existe o movimento dos bancos pós-relacionais ou NoSQL, onde o JPA é simplesmente a abstração errada. Portanto, abandonar DAO (e usar os EntityManagers diretamente) pode não ser uma vantagem se considerarmos todas as ofertas de persistência.

Ola Leonardo

Acho que é bem por aí mesmo. Sua opinião está mais para o lado do Vincent (a minha também é para esse lado). Curioso a Sun não se posicionar nesses anos todos em relação a essas boas práticas, e ficarmos com o Core J2EE Patterns mais que outdated.

Penso que depende do projeto e de como esta o resto de sua modelagem.
Quem vem do Java do período jurássico after ORM, lembra de:

  • GenericFirebirdDAO implements GenericDAO
  • CustomerOracleDAO implements CustomerDAO
  • NotaFiscalMySQLDAO implements NotaFiscalDAO
  • RapaduraPostgresDAO implements RapaduraDAO

… maravilha, conseguimos ter nosso projeto "multi-banco".
A idéia era abstrairmos o banco, ja que as instruções SQL sempre tinham suas particulariedades lock-in. A vantagem comercial é clara.

Com as ORMs, começamos a pensar diferente. Vou fazer a persistencia em JDO pra abstrair o banco, mas e se quiser mudar para o Apache OJB, KODO ou Prevayler? Vou fazer em Hibernate, mas e se quiser mudar para o iBatis? E por aí vai… então começaram a "era" dos:

  • CustomerHibernateDAO implements CustomerDAO

… maravilha, temos nosso projeto a prova de mudança de tecnologia. Hmm, mas quantos deles realmente mudamos de tecnologia? Quantos projetos reescrevemos "toda" camada de persistencia de Hibernate para qualquer outra coisa? Pessoalmente, ja vi muito dinheiro com horas de desenvolvimento sendo jogadas fora para interfaces cuja implementação nunca passou de uma classe concreta/per interface.

Mas vamos misturar regras de negócio com códigos de banco? Pra isso temos outros padrões como ActiveRecord, Repository, QueryObjects etc. DataAcessObject quase sempre é implementação de DataMapper, e para isso os ORMs fazem bem o papel. Os outros padrões tem características diferentes e não são de fato DAOs.

Logo, hoje, se utilizo um desenvolvimento like DDD, uso Repository para fazer parte do codigo com uma implementação onde a API do ORM é exposta… aos moldes de Applying-Domain-Driven-Design-Patterns-Examples. Se o projeto não justifica um domain-driven, descarto repository (embora um possa existir sem o outro). Neste caso utilizo EntityManager com suas NamedQueries diretamente, sem medo de ser feliz, chutando pra longe aqueles DAOs onde tinha :

  • dao.save() -> entityManager.persist()
  • blaDao.buscarBlaMaiorQueFulano() -> entityManager.createNamedQuery(?bla.buscarBlaMaiorQueFulano?)

Quase sempre, não sinto falta neste caso dos DAOs. "Quase", pq quando se fala em testes unitários…hmm. Nisso tendo a granularidade em DAOs ou Repositories pode lhe ajudar mais do que atrapalhar.

Paulo, os BluePrints do JavaEE 5 da SUN mostram que "ModelFaçade" é a bola da vez para abstrair as chamadas a JavaPersistence API. DAOs estão fora da jogada:
https://blueprints.dev.java.net/bpcatalog/ee5/persistence/

Alessandro, mais um excelente post seu, obrigado!

Mas quando sua named query nao é suficiente para trazer o que você precisa, e você precisa de um pós processamento da sua lista de entidades (seja para sumarizar alguma infiormação, seja para uma operação em lote de “data logic”), onde você poe isso?

E de qualquer maneira esse ModelFacade esta bem próximo de um DAO, correto? (vale lembrar da Sun ser campeã em renomear patterns :), esse nome é novo pra mim, apesar da composição obvia, e não encontro referencias em outros lugares).

PS: o King costuma dizer que o Hibernate é quem faz o papel do DataMapper, nao o DAO, mas sinceramente se formos dar atenção a como cada um usa a nomenclatura, vamos achar 100 opções diferentes.

Concordo com a idéia de que o entityManager faz o papel de DataMapper.

Eu gosto de criar uma camada (Que não vou chamar de DAO), onde isolo o uso do entityManager e as queries do negócio.

Faço isso para manter o SRP (Single Responsability Principle). Esse isolamento ajuda muito nos testes unitários, pois eu posso mockar essa camada inteira e testar apenas a lógica da aplicação, sem precisar subir um banco de dados/hibernate para testes (o que aumentaria consideravelmente o tempo de execução dos testes).

Concordo com a opinião que nunca mudei de tecnologia de persistencia durante um projeto, porém, crio essa camada não com o objetivo de poder mudar a tecnologia, mas sim com o objetivo de manter “cada coisa no seu lugar” - Cada camada com sua responsabilidade.

[]s

Olá Paulo,

Eu concordo com o Leonardo e com o Lazarotti, DAO ainda tem seu lugar e não morreu por causa do JPA.

Basicamente DAO tem seu lugar ainda nas aplicações e deveria ser utilizado nos casos em que faz sentido. O problema, na minha opinião, é que o pessoal tende a replicar DAOs por todos os lugares da aplicação, principalmente para CRUDs e relatórios quando na verdade o DAO está atuando apenas como um wrapper.

Uma coisa que ainda não me entra na cabeça é ter uma DAO layer para tentar abstrair a tecnologia (como citado pelo Lazarotti). Quando se decide por uma tecnologia como JPA/Hibernate você deveria se preocupar mais em aproveitar os recursos da tecnologia a evita-los pelo simples fato de achar que futuramente você poderá mudar de tecnologia.

Oi Rafael

Vendo seu blog, que no ultimo post fala de DAO, voce comenta que algumas pessoas argumentam assim:

Concordo totalmente que esse não deve ser a justificativa essencial para um DAO. Se só posso nomear como DAO alguem que vai me abstrair se uso JDBC/JDO/JPA, realmente nao chamaria minha classe de DAO, e sim de alguma outra coisa (ModelFacade? como o Alessandro linkou pro beta do catalogo de patterns do Java EE 5).

Acho legal um trecho do wikipedia, que fala As is common in Java, there are many open source and commercial implementations of DAO available. Each of these can have potentially different implementation strategies and usage models. There is a familiarisation curve involved with each of them, realmente cada um faz de um jeito e leva o pattern de um lado pro outro.

Sinceramente eu não concordo que DAO deva existir depois do JPA.

Criar classes que estão basicamente sendo tratadas como delegates (como DAOs JPA-based) chega a ser uma maneira de “socar” camadas no sistema, aumentando a complexidade e deixando as classes com excesso de coesão. Não que eu ache que coesão seja algo ruim, pelo contrário, mas quando as definições ficam assim,“forçadas demais”, dá a impressão que o sistema fica meio feio, sei lá.

Querendo ou não, os EntityManagers já atuam como DAOs genéricos.

Além disso, temos a interface EntityManger que é facilmente “stubável” ou “mockável”, eu poderia citar que as vantagens de se utilizar DAOs era a facilidade de ser unit-tested, mas pelo visto não há tantas diferenças não.

Agora, se há chances do sistema trocar de ORM pra JDBC ou qualquer outra coisa, aí sim pode ser que seja necessário criar DAOs. O problema é que nem sempre é assim e o pessoal gosta de se preocupar com apocalypses que mal foram previstos, é como aquela palestra que teve no falando em Java, sobre as “leis” do arquiteto, algo como “se preocupar com performance quando não se há necessidade”, apesar das coisas serem completamente diferentes, a idéia de se preocupar com algo que nem se sabe se haverá é a mesma.

Pela experiência que tive até hoje, o que eu concluí foi isso. Já trabalhei com sistemas multibanco, usando DAO com JPA mas não achei muiiiitas vantagens não.

Oi Leozin

mas entao onde voce colocaria um método que envolve “data logic”? por exemplo para criar um objeto para diversos relatórios, que é uma combinação de dados de diversas entidades?

Eu ainda sou defensor dos DAOs, principalmente pela questão de facilitar os mocks na hora dos testes.

Um efeito colateral bom que eu já peguei, foi uma mudança de tecnologia (sim, muito tosca), que jogou parte do que estava no banco pra um GED. Como já tinhamos DAOs (bem magros por sinal), bastou mudar a implementação.

Acho que o tempo perdido é muito pequeno em vista do benefício, então…

IMHO, sempre

Paulo, o que tenho aplicado é usar Repositórios como interfaces (só para se beneficiar de DI) e com uma implementação que depende do EntityManager. Abandonei o nome DAO, pois o padrão significa mapeamento para o banco, e como o Hibernate faz isso para nós não vejo sentido em usar essa nomenclatura.

Para falar a verdade, estou para blogar sobre Repositórios… vou ver se adianto isso hoje e aí posto aqui para colaborar…

[quote=Paulo Silveira]Oi Leozin

mas entao onde voce colocaria um método que envolve “data logic”? por exemplo para criar um objeto para diversos relatórios, que é uma combinação de dados de diversas entidades?[/quote]

O ideal mesmo era colocar um repository no teu service, algo de “nível mais alto” se não quiser misturar “tanto” persistência com negócios.

Isso se tu quiser abstrair mais ainda, porque o EM já abstrai muitas coisas na minha opinião, ainda mais se tu trabalhar com NamedQueries por exemplo.

[quote=Paulo Silveira]Oi Leozin

mas entao onde voce colocaria um método que envolve “data logic”? por exemplo para criar um objeto para diversos relatórios, que é uma combinação de dados de diversas entidades?[/quote]

Pois é, esse é o ponto.

Eu tbm nao concordo em ter toda aquela hierarquia DAO como propunha o padrao a principio. Mas será que é uma boa ter o codigo de acesso aos dados (Session, EntityManager, etc…) misturado as regras?

Eu tbm vou pelo caminho dos repositorios, mas as ideias que rechaçam os DAOs tbm nao podem ser aplicadas aos repositorios? Afinal eu nao estaria criando uma camada pra, em grande parte dos casos, somente traduzir os metodos do EntityManager.

Mas especifamente esse exemplo que vc deu , eu acho que torna clara a razao da existencia de um repositorio.

acho que não devemos esquecer os principios do padrão de projeto DAO. :slight_smile:

Context
Access to data varies depending on the source of the data. Access to persistent storage, such as to a database, varies greatly depending on the type of storage (relational databases, object-oriented databases, flat files, and so forth) and the vendor implementation.

Fonte:
http://java.sun.com/blueprints/corej2eepatterns/Patterns/DataAccessObject.html

[quote=diegosantiviago]acho que não devemos esquecer os principios do padrão de projeto DAO. :slight_smile:
[/quote]

Oi Diego. Realmente se usarmos a definição da Sun, encapsular as queries e lógica de dados não se encaixa como um DAO. Então o que seria essa classe?

só um adendo: eu fico perdido em discussões em que todo mundo tem um ponto válido e que concordo com todos eles!

hahahahaha é verdade

Mas Paulo, tu já percebeu o tanto de design patterns que “desapareceram” quando o JEE 5 apareceu?

Digo, existe ainda business delegate? service locator? dao? dto? Em ambiente JEE 5?

Alguns design patterns no j2ee foram feitos exatamente para suprir determinados pontos falhos, como por exemplo, o citado no falando em java ano passado (denovo rs), o DTO/TO/VO para evitar as chamadas RMI no servidor em Entity Beans quando se ia acessar uma determinada propriedade.

Sinceramente, focando no assunto do tópico, não acho que “seja errado” criar DAOs com EntityManagers, mas é que, vai variar de acordo com o sistema que tu vai desenvolver, e que na maioria das vezes, vale mais a pena trabalhar com um EntityManger e com/sem repositories do que JDBCDAO ou JPADAO.

Em um dos sistemas que trabalhei, a hierarquia era assim:

[code]
public interface PersonDAO {

public void createPerson(Person person);

}[/code]

[code]public abstract class BaseJPADAO {

protected EntityManager em;

protected Query createNamedQuery(String query) {
// A named query template method
}
}[/code]

public class JPABasedPersonDAO extends BaseJPADAO implements PersonDAO { public void createPerson(Person person) { em.persist(person); } }

Lembrando que caso haja interesse de usar um JpaTemplate/JdbcTemplate do Spring, pode-se colocar no Base* de algum DAO.

Como a programação era voltada a interfaces, ficava fácil de trocar caso houvesse necessidade de criar uma versão JDBC, outra JPA, outra iBatis e assim por diante, porque as classes Base serviam para colocar alguns templates methods até pra ter uma melhor reutilização do código.

Não lembro se os nomes das classes eram exatamente assim, porque ficou feião hehehe vou ver se consigo reviver o código de lá e mostro pra vocês verem o que acham, mas pelo que eu me lembre, só mudou o nome das classes mesmo, porque a maneira que foi implementado é a mesma.

oi leozin

entedi e concordo com seu exemplo sim, que ai vira so um wrapper.

mas e na hora que voce tem “data logic” e names queries não são suficientes? a classe em que voce concentra isso, como chama?

ah! e DTO ainda tem seu espaço quando voce precisa ajustar a granularidade (mas realmente nao é mais um “pattern obrigatorio”, ja que ejb3 engoliu as deficiencias do 2…)

Sou contra o uso de DAO’s indiscriminadamente alem de fazer mal a saude do sistema faz com que alguns programadores tenham dor de barriga, no caso de data logic o DAO serviria bem, ninguem quer um wrapper sem sentindo a mais pra se preocupar…

Ateh gostaria de perguntar alguem por ai jah teve que trocar o mecanismo de persistencia? O DAO ajudou?