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

Nesse debate estou vendo dois pontos importantes

1º - Encapsular as chamadas ao EntityManager OU Chamar diretamente o EntityManager.

2º - A forma de implementação do acesso ao Entity Manager ou pelo DAO, ou por Facede, ou por Repository, ou outros. Como o Paulo falou:

São bem próximas. Acho que no final acabamos chegando no mesmo lugar usando várias formas diferentes. E todas, ao meu ver, certas.

Acho que é muito mais complexo essa discussão, pq vai entrar no gosto do Arquiteto da aplicação. Um pode gostar de Usar JPADao e seus *DAO. Outros preferem usar Facede e assim é a vida. Cada um faz como acha melhor fazer, mas como o Paulo falou o problema não é a prática é o nome que está se dando as nomeclaturas.

[quote=rodrigoy]Amigos,

DAO é um padrão de infra… Repository é um padrão de domínio…

(vou tentar terminar meu blog post ainda hoje, mas por enquanto, pensem no diagrama abaixo)

É o domínio que vai direcionar os seus repositórios.[/quote]

O que acho interessante é que eu faria desse jeito. Mas estranhamente, chamo tanto “Repository” quanto “DAO” de “DAO”, porque não consigo olhar um objeto façade e dizer: “esse é de infra”, “aquele é de domínio”.

Outra coisa que eu gosto de fazer é não fazer do “DAO” um façade especial, ou de categoria diferente. Por exemplo, se estou usando o EJB3, os DAOs serão Stateless Session Beans, assim como qualquer façade de negócio; ou se estou usando Spring, os DAOs serão também beans do Spring.

Assim, no “hardcore” do sistema, haveria façades de negócio acessando os DAOs necessários; enquanto que nos CRUDs da vida, os DAOs seriam acessados diretamente pelos Actions/Components/Managed Beans/Controllers dos frameworks MVC.

[quote=Leonardo3001]
O que acho interessante é que eu faria desse jeito. Mas estranhamente, chamo tanto “Repository” quanto “DAO” de “DAO”, porque não consigo olhar um objeto façade e dizer: “esse é de infra”, “aquele é de domínio”.[/quote]

Olha só o exemplo que o king_of_gods deu na página anterior:

[code]public class BaseDAO<T> {
private EntityManager manager;

  /* Métodos Comuns */

}[/code]

public class CarroDAO&lt;Carro&gt; extends BaseDAO&lt;Carro&gt; { public List&lt;Carro&gt; retornaQtCarrosVendidosUltimoSemestre() {...} }

Esse é o melhor exemplo que o rodrigoy quis se referir pelo diagrama.

na verdade, abstraindo para Repository, seria assim:

public class CarroRepository { public List&lt;Carro&gt; retornaQtCarrosVendidosUltimoSemestre() { // algum código randômico Date dataFinal = new Date(); Date dataInicial = getDataSemestre(); return dao.buscarPorPeriodo(dataInicial, dataFinal); } }

public class CarroDAO&lt;Carro&gt; extends BaseDAO&lt;Carro&gt; { public List&lt;Carro&gt; buscarPorPeriodo(Date dataInicial, Date dataFinal) {...} }

Você fazer uma busca por período não é domínio. Agora, uma regra de negócio aplicada nele, aí sim fica legal.

O DAO, na minha opinião, se utilizado, não deve envolver regras de domínio e sim, somente facilitar o acesso a dados que estão persistidos em algum lugar. Encapsular e deixar as queries dinamicas, fazer inserções em N lugares, excluir logicamente etc.

Olá

A discussão está muito boa e só quero arranjar um jeito de receber por email quando este tópico for atualizado. Então vou colocar 2 links (de um cara que nem sempre gosto por ser muito JEE biased):

http://www.adam-bien.com/roller/abien/entry/jpa_ejb3_killed_the_dao
… The DAO pattern is actually no more interesting for general data access, but is still needed to access data from stored procedures, flat files etc. …

http://www.adam-bien.com/roller/abien/entry/daos_aren_t_dead_but

… you could easily use the EntityManager directly in your Service layer and if you notice some repetition or duplication just to refactor the code into one place…
… in J2EE, however, you would start with a DAO in own layer, in Java EE a DAO can just evolve but is optional…

[]s
Luca

Leozin,

Podemos fazer algo muito parecido com o Repository usando Facade.

interface CarroFacade { public List<Carro> retornaQtCarrosVendidosUltimoSemestre(); }

public class CarroFacadeImpl implements CarroFacade { public List<Carro> retornaQtCarrosVendidosUltimoSemestre() { // algum código randômico Date dataFinal = new Date(); Date dataInicial = getDataSemestre(); return dao.buscarPorPeriodo(dataInicial, dataFinal); } }

Dois Patterns para a mesma solução. Duas forma elegantes de fazer a msm coisa.

Uma coisa que eu gostei pacas foi essa de só deixar o DAO “executar SQL”. Realmente, estava errado no pensamento anterior. Acho mto mais “elegante” e fácil tratar o domínio dessa forma.

(voltando de férias e entrando no debate)

Me parece que a maioria concorda que o DAO como pattern para encapsular totalmente o BD para depois trocar a camada de persistência é furada. Alias, algo que as vezes nao pensamos é que mtas coisas da JPA vazam para o modelo mesmo quando usamos DAO como por exemplo as classes de ID para chaves compostas e outras ideias.

Mas pra mim parece estranho colocar o EM espalhado pelo dominio todo. Aqui to fazendo igual ao Yoshima, o Taborda e outros: uma interface pro repositorio dentro do domain model encapsulando as operacoes e outra implementacao em algum canto. As razoes principais pra isso sao tests e SoC (como o taborda falou).

Hoje eu dou o nome de DAO a essa implementacao do Repositorio por força do habito mas confesso que tbm estou atras de um novo nome. (e sinceramente ModelFaçade é horrivel)

E um ultimo adendo: como o Yoshima falou, o DAO é um padrao de infra. Mas uma coisa bem esquisita é ter um ProdutoDao na infra que depende de coisas do domínio, como a propria classe Produto. Discuti isso certa vez com o Calçado e ele falou que tambem estava se sentido incomodado com isso mas nao havia mto jeito de fazer diferente. Alguem ai falou de encarar o Hibernate/ORM como infra. Eu sinceramente to pensando em encarar o RepositoryImpl (sem chamar de DAO) como dominio e dependendo do EM que é infra.

Só gostaria de reiterar que sugeri utilizar diretamente o EntityManager apenas para create, update e delete. Não sugeri em momento algum utilizá-lo no lugar de repositórios para recuperar os dados.

como eu disse… todos bem alinhados :slight_smile:

Concordo com o que vc disse Taborda, mas não me refiro “as Services” que são adendos ao Domain Model. Me refiro as services da própria Service Layer (ou Application), ou seja, aquele modelo de Services a qual aproveitamos a própria injeção do persistence em uma SessionFacade, por exemplo.

Este é o ponto Yoshi, infelizmente elas interferem, principalmente em certos nichos. Se vc esta trabalhando com licitações, no papel de consultor da arquitetura, onde alguma “Fabulosa Fábrica de Softwares” será responsável pela implementação (e vc não sabe qual), fica muito difícil sugerir uma arquitetura que seja plenamente aderente ao domínio (aqui me refiro em todas as praticas para tal, incluindo repository). Primeiro pq modelagem e desenvolvimento comprometido com domínio, implica em cultura que a maioria das fabricas de softwares não tem.

Neste caso, descartar repositories pode diminuir o risco de “apenas utilizar o nome do padrão” e a implementação ser qualquer coisa, menos o referido. Assim, utilizar um entitymanager direto nos Services (como citei acima pro Taborda), pode ser mais viável para a realidade da equipe.

Que fique claro que não defendo sacrificar SoC, só digo que nem sempre o que gostamos ou desejamos implementar, seja de fato implementável por quem vai fazer o serviço (bem infelizmente).

Acho que depende qual fase de testes vc esta rodando Yoshi. Para testes unitários, se vc tem um repository no lugar de EntityManager/Session direto no código a ser exercitado, fica mais fácil isolar o comportamento do método criando mock de seu repositório. Se vc não tem a interface do Repository, mockar EntityManager não rola na prática (ou rola de maneira totalmente sacal) e acabamos por não conseguir testar de forma totalmente isolada a unidade, só em integração.

Eu comecei uma discussão relacionada faz quase 2 anos e a conclusão que cheguei foi que vale a pena ter o Repositório acessando o EntityManager.

http://guj.com.br/posts/list/74599.java

Quanto ao DAO, acho desnecessário na maioria dos casos. De qualquer forma, ainda continuo com a opinião de que quando criaram a dupla EntityManager/Criteria, a idéia que os caras tinham era um Repositório genérico com Criteria genérico. Lógico que é uma suposição minha. Confesso que na época isso me confundiu bastante, só que como a interface do EntityManager cheira a infra-estrutura e temos alguns problemas com testes me convenci de que não fica muito legal deixar o EntityManager espalhado pela aplicação. Portanto, geralmente tenho um Repositorio na frente do EntityManager quando uso JPA|Hibernate.

Aproveitando a discussão,

O livro Patterns of Enterprise application architecture cataloga um pattern chamado queryObject. Acompanhando a discussão, pensei na possibilidade de ter uma camada de persistência considerada como Infraestrutura, e essa camada saberia traduzir os QueryObjects para queries jpa ou qualquer que seja a tecnologia de acesso a banco.

Neste caso os queryObjects seriam objetos de negócio, como Specifications, que poderiam ser utilizados pelo domínio.

Alguem já fez uma implementação parecida com isso? Será que vale a pena?

[]s

[quote=Leonardo3001][quote=rodrigoy]Amigos,

DAO é um padrão de infra… Repository é um padrão de domínio…

(vou tentar terminar meu blog post ainda hoje, mas por enquanto, pensem no diagrama abaixo)

É o domínio que vai direcionar os seus repositórios.[/quote]

O que acho interessante é que eu faria desse jeito. Mas estranhamente, chamo tanto “Repository” quanto “DAO” de “DAO”, porque não consigo olhar um objeto façade e dizer: “esse é de infra”, “aquele é de domínio”.

Outra coisa que eu gosto de fazer é não fazer do “DAO” um façade especial, ou de categoria diferente. Por exemplo, se estou usando o EJB3, os DAOs serão Stateless Session Beans, assim como qualquer façade de negócio; ou se estou usando Spring, os DAOs serão também beans do Spring.

Assim, no “hardcore” do sistema, haveria façades de negócio acessando os DAOs necessários; enquanto que nos CRUDs da vida, os DAOs seriam acessados diretamente pelos Actions/Components/Managed Beans/Controllers dos frameworks MVC.[/quote]

Olá, concordo totalmente com a afirmação. Também não consigo ver essa diferença entre “Repository” e “DAO”, ate mesmo na questaos dos packages do JAva, fica estranho ter o Repository no package domain e o DAO no infra, ou persistence.
Então o que costumo ter hoje, e um DAO<T> generico que encapsule um EM, ou Session, e ter os metodos basicos, além de metodos que facilitam bastante como o findByExample do Hibernate, isso evita findByX, findByXX, ou seja so criou outro DAO se for uma pesquisa bem especfiica.

Esse DAO é chamado do Service, ou em casos de CRUD apenas, são chamados dos ManagedBeans/Actions etc.

Desta forma, consigo resolver os problemas facilmente, sem criar camada "ocas", e descenecessárias. Houve um tempo em que eu tinha:

Repository -> RepositoryImpl-> Dao->DaoImpl

Mas na minha opinião em 90% dos casos isso e um overkill, hoje tento ser mais simples possível.

Valeu

todo mundo do guj praticamente concordando com todo mundo
sinal do fim dos tempos? ou paz mundial? :slight_smile:

obrigado pessoal, agradeco a ajuda!

[quote=Ferryman]Aproveitando a discussão,

O livro Patterns of Enterprise application architecture cataloga um pattern chamado queryObject. Acompanhando a discussão, pensei na possibilidade de ter uma camada de persistência considerada como Infraestrutura, e essa camada saberia traduzir os QueryObjects para queries jpa ou qualquer que seja a tecnologia de acesso a banco.

Neste caso os queryObjects seriam objetos de negócio, como Specifications, que poderiam ser utilizados pelo domínio.
[/quote]

QueryObject é o nome do padrão de projeto usado pelo Hibernate e pelo JPA2 nos seus Criteria.
A diferença é que para essas cadas o Criteria é atrelado ao mecanismo e portanto não é genérico.
O que quero dizer com isto é que essa ideia já usada, mas não em toda a sua potencialidade.

A ideia que melhor modela o acesso a dados é o Repositorio criando QueryObject genéricos e passando a um terceiro objeto que os interpreta para a tecnologia de acesso.

Vale com certeza a pena. Eu já usei mas com interpretação directa para JDBC. Passar pelo JPA ou Hibernate não funciona porque esse mecanismos têm vazamento para os objetos das entidades. Tlv sem anotações funcione melhor ou com mecanismos avançados do hibernate puro (sem JPA)

O Criteria Toolbox do MiddleHeaven propõe exatamente um modelo genérico guiado por critérios genéricos que tanto podem ser aplicados a um Collection como a um Banco ou a um XML. Isto permite uma clara separação entre o que é da aplicação o que é do dominio e o que é de infra. (DAO não são infra, são de aplicação ) Para isso ele implementa o padrão DomainStore que é o padrão de fato para isolamento de acesso a dados utilizando domínios.

[quote=Ferryman]Aproveitando a discussão,

O livro Patterns of Enterprise application architecture cataloga um pattern chamado queryObject. Acompanhando a discussão, pensei na possibilidade de ter uma camada de persistência considerada como Infraestrutura, e essa camada saberia traduzir os QueryObjects para queries jpa ou qualquer que seja a tecnologia de acesso a banco.

Neste caso os queryObjects seriam objetos de negócio, como Specifications, que poderiam ser utilizados pelo domínio.

Alguem já fez uma implementação parecida com isso? Será que vale a pena?

[]s

[/quote]

Pra mim, o Query Object não tem uma diferença muito grande de uma Criteria, na verdade é uma criteria simples.

Aí eu já acho viagem demais, se tu usa hibernate. Se tu tá usando JDBC por exemplo, até pode ser, mas acho que na maioria dos casos, usar Query Object foge totalmente do principio do KISS.

Na realidade é o Criteria que é um Query Object simples.
Não existe nenhuma consideração sobre o quão um QueryObject pode ser complexo. QueryObject pode ser desde um bean até … Deus sabe. Normalmente ele não precisa ser muito complexo. É o builder dele que é, ou se não houver builder, o conjunto de classes que auxiliam a criação do objecto.

Bem pelo contrário. Se fosse assim ele não seria um padrão de projeto.
Tlv não pareça mas um QO é mais simples que uma frase SQL, mesmo se não acompanhado de builder.
Só o fato de ser um objeto per se (e não apenas um string) ajuda bastante.

[quote=sergiotaborda]Bem pelo contrário. Se fosse assim ele não seria um padrão de projeto.
Tlv não pareça mas um QO é mais simples que uma frase SQL, mesmo se não acompanhado de builder.
Só o fato de ser um objeto per se (e não apenas um string) ajuda bastante.[/quote]

Então quer dizer que mesmo você usando Hibernate, tu iria criar Query Objects mesmo tendo o Criteria nas disponível?

ps.: Sim, Criteria é uma implementação de Query Object.

[quote=Alessandro Lazarotti]
Acho que depende qual fase de testes vc esta rodando Yoshi. Para testes unitários, se vc tem um repository no lugar de EntityManager/Session direto no código a ser exercitado, fica mais fácil isolar o comportamento do método criando mock de seu repositório. Se vc não tem a interface do Repository, mockar EntityManager não rola na prática (ou rola de maneira totalmente sacal) e acabamos por não conseguir testar de forma totalmente isolada a unidade, só em integração.[/quote]

Exato, é por ae mesmo, Lazarotti.

Utilizar EntityManager diretamente em vez de DAOs faz sentido (e provavelmente será mais utilizado) na camada de aplicação [Application Layer], na maioria dos casos para funcionalidades relativamente simples sem muita lógica (inclua CRUDs aqui) em que fica quase claro a não necessidade de alguma camada de indireção apenas por convenção da arquitetura. O pattern tem seu papel e deve ser utilizado onde se precisa e não em todos os lugares só porque fica mais “comodo”.

Se houver necessidade de fazer alguns testes unitários em que seja complicado mockar o EntityManager então acredito que neste lugar seja melhor um DAO ou mesmo Repository. Para os demais casos testes de integração pode ser um melhor caminho.

O importante é não generalizar tudo apenas por questões de convenções da arquitetura.

[quote=Leozin][quote=sergiotaborda]Bem pelo contrário. Se fosse assim ele não seria um padrão de projeto.
Tlv não pareça mas um QO é mais simples que uma frase SQL, mesmo se não acompanhado de builder.
Só o fato de ser um objeto per se (e não apenas um string) ajuda bastante.[/quote]

Então quer dizer que mesmo você usando Hibernate, tu iria criar Query Objects mesmo tendo o Criteria nas disponível?
[/quote]

Não.
Embora seja possivel criar um QO genérico e depois interpretá-lo para um criteria do hibernate e executar em cima do hibernate, como eu disse isso não é realmente genérico porque as entidates precisam de controle do hibernate. Então não ha vantagem em ter um QO no meio.

Veja a analogia

Arquitetura geral : algumacoisa -> repositorio -[monta] – > QueryObject | repositorio – [executa QO sobre] --> DomainStore

Arquitetura com hibernate : algumacoisa -> repositorio -[monta] --> Criteria | reposiotiro-- [executa Criteria sobre] --> Hibernate

[quote=rponte]
Se houver necessidade de fazer alguns testes unitários em que seja complicado mockar o EntityManager então acredito que neste lugar seja melhor um DAO ou mesmo Repository. Para os demais casos testes de integração pode ser um melhor caminho.

O importante é não generalizar tudo apenas por questões de convenções da arquitetura.[/quote]

hummm… Uma regra importante na moda, no design e na arquitetura e que se aplica aqui é : less is more.
Menos é mais. O que singifica isto ? Básicamente significa que mesmo que vc possa fazer algo (Adicionar) isso não significa que deva.

O que separa o poder do dever e do fazer é uma linha ténue , dificil de enxergar e que requer algum tipo de visão especial tipo visão de raio-X do super-homem. O que quero dizer com isto é que é facil dizer “não vamos fazer isso porque a arquitetura manda, vamos fazer isto aqui porque é mais simples” … o buraco escorregadio aqui é o que significa “simples”. Para os mais desatentos “simples” significa “mais depressa” ou “já sei fazer”. Ora isso é uma forma muito egoísta de olha a construção do sistema. “Simples” deve significar isso mesmo “simples” e não “o jeito que eu achei mais rápido para tirar o meu da reta” ( isto tem outro nome : gambiarra).
Cada vez decide não pensar, estudar ou pesquisar sobre um problema e tira uma solução da cartola vc está criando mau design (aka gamb) que no fim vai vir de noite e engolir você… não veio ainda? é porque ainda está no fim.

Só porque existe um jmock isso significa que posso sair por ai mockando todo e qualquer objeto ?
Se levarmos à letra sim, mas se usarmos o principio do menos é mais, mockar menos é melhor. Mockar Thead seria impossível ou quase tão dificil como criar um novo mecanismo de paralelismo. Fazer um mock tem que ter um objetivo e tem que ser o ultimo recurso. Por exemplo, se vc tem um serviço com interface S e quer criar um tipo particular para usar em testes vc criar uma implementação STest. Repare que vc está criando um mock, mas não usando uma ferramenta de mock. Isso significa , então , que vc está implementando uma outra “encarnação” de S. Isso é extremante util para entender se o design de S está correto ( é desacoplado e conciso) , se o seu tratamento/modelagem de exceção é coerente e util, se os tipos de retorno e entrada são genéricos e simples de construir. Usando o jmock vc não entenderia isso.

Acho que - e não é de agora - a maioria aqui vê o filme ao contrário. Todo o mundo fala que “generalizar” é mau. Se fosse tão mau assim , será que OO seria baseado em abstrações - que são uma forma de generalização ? Não.

Quando vc pensa em design vc pensa em abstrato. Vc imagina contratos, interfaces, trocas de mensagens. Vc não imagina codigo, classes, corpos de método, ou fica preocupado com o tempo de codificação.

Codificar um hibernate da vida é extremante complexo. Existem muitos items ligados a performance. Mas o modelo ? o modelo é o mais abstrato que pode ser. E ai que está o poder dessa biblioteca, não na sua implementação.

Programadores utilizam-se dos contratos dos objetos, nãos das implementações. Então, um bom codigo, um bom design, um bom sistema é aquele que tem bons contratos.

Enfim, tudo isto para dizer que não é irrelevante a escolha entre isolar ou não o entitymanager. isolá-lo é inerentemente mais vantajoso e isso, eu acho, é muito obvio. Se essa a forma que minimiza todos os problemas, porque usar outra ? mesmo que essa outra pareça mais simples , não será a melhor.

Porquê negar o que é bom ? isso não faz sentido para mim.