Essa seria uma má prática para JPA?

11 respostas
H

Eu estou migrando alguns sistemas de php e forms & reports para java.

Em casos em que há uma query que envolve diversas tabelas eu não quero carregar todos os atributos de todas essas tabelas, eu crio uma classe de entidade exclusivamente para receber o resultado da minha query. Por exemplo:

Nesse caso eu criaria a seguinte classe:

@Entity public class Resultado{ @Column(name="a.atributo1") private String atributo1; @Column(name="a.atributo2") private String atributo2; @Column(name="b.atributo3") private String atributo3; @Column(name="c.atributo4") private String atributo4; }

No facade então eu apenas executo uma nativeQuery. Assim consigo obter o resultado e facilmente transmití-lo para o meu managed bean poder usá-lo.

public Resultado findResultado() { return (Resultado) em.createNativeQuery("SELECT a.atributo1, a.atributo2, b.atributo3, c.atributo4 FROM a, b, c WHERE (...)", Resultado.class).getSingleResult(); }

Deste modo consigo obter as seguintes vantagens:
[list]Reaproveito queries que já estão prontas SQL (através do nativeQuery). Como consequência levo muito menos tempo na implementação do que se eu tivesse que passar tudo para JPAQL utilizando as entidades do meu banco de dados;[/list]
[list]Retornar um simples objeto para meu managedBean, com todos os atributos facilmente acessíveis através de apenas um get.[/list]

Porém eu estou preocupado se essa seria uma boa prática a longo prazo e gostaria de outras opiniões.
[list]Será que essas entidades não prejudicariam a manutenibilidade do projeto?[/list]
[list]Eu poderia ter algum tipo de problema futuramente?[/list]

11 Respostas

paulo1911

Olá amigo,

Na minha opinião é uma má pratica sim. Pois o JPA para essa sua questão de reutilizar SQL ja existe as namedQuery.
Mas isso vai depender do padrão de projeto que vc vai estar aplicando no seu projeto.
Eu prefiro usar JPQL ou HQL do hibernate mesmo e mapear os relacionamentos com lazy e fazer join com hql para trazer dados relacionados quando necessário.

Essa é minha opinião sobre a questão.
fallow

A

cara,

como vc mostrou na sua query, a, b e c , são tabelas do seu banco, entao vc vai ter que mapear essas tabelas para entidades, com isso fica todo orientado a objeto.

t+

D

O único problema é que os parâmetros estão “amarrados” na query, ou seja, se quiseres adicionar algum parâmetro novo para retorno, será necessário alterar a query. E alterar a query as vezes é problema, pois é necessário testar novamente todas as funções que utilizam ela.

Fora isso o restante parece estar bem feito.

ps. Eu também utilizo esta forma para mandar dados para o managedBeans quando é nativeQuery, ou fazendo uma classe DTO para receber os dados, e instancia esta classe DTO direto na HQL.

H

paulo1911:
Olá amigo,

Na minha opinião é uma má pratica sim. Pois o JPA para essa sua questão de reutilizar SQL ja existe as namedQuery.
Mas isso vai depender do padrão de projeto que vc vai estar aplicando no seu projeto.
Eu prefiro usar JPQL ou HQL do hibernate mesmo e mapear os relacionamentos com lazy e fazer join com hql para trazer dados relacionados quando necessário.

Essa é minha opinião sobre a questão.
fallow

Por curiosidade, existe alguma diferença prática entre utilizar as queries como namedQuery ou nativeQuery? Pelo que entendi meio que só muda o local em que a query está armazenada, já que não consigo imaginar o reaproveitamento de uma mesma query.

E o mapeamento como lazy só vale para os objetos das tabelas relacionadas, não? Os outros campos (varchar, short, int, etc) não seriam carregados sempre, mesmo quando não fossem necessários?

H

duducordeiro_:
O único problema é que os parâmetros estão “amarrados” na query, ou seja, se quiseres adicionar algum parâmetro novo para retorno, será necessário alterar a query. E alterar a query as vezes é problema, pois é necessário testar novamente todas as funções que utilizam ela.

Quando quero adicionar algum novo parâmetro de retorno, eu simplesmente adiciono uma nova variável na classe, adiciono a anotação @Column(name=“nome_do_novo_atributo”) e adiciono o atributo no retorno na query.

alissonvla:
como vc mostrou na sua query, a, b e c , são tabelas do seu banco, entao vc vai ter que mapear essas tabelas para entidades, com isso fica todo orientado a objeto.

Eu não teria problemas em fazer assim, o único empecilho para mim é poder carregar apenas os atributos destas 3 tabelas que eu quero. Por exemplo, se eu quero apenas 1 entre 10 atributos da tabela a, eu gostaria de carregar apenas este único atributo necessário.

Quando faço uma query que lida com apenas 1 tabela, eu posso fazer isso com um construtor, porém quando há diversas tabelas, a única forma que consegui imaginar foi criar uma entitade para mapear o resultado da query.

A

cara,

como suas entidades vao estar todas OO, entao vc nao teria problema em criar um construtor, que vc preencha mais de uma entidade.

t+

rmendes08

Cara, acho que do jeito que você fez está certinho. Pelo o que eu entendi, você precisa de algumas colunas que são resultado de um join com várias tabelas correto ? Bom, se as tabelas não estão mapeadas em entidades então você tem que usar uma query nativa mesmo. Na pior das hipóteses, pegue o resultado com array de objetos e faça na mão. Na minha opinião, só vale a pena mapear as tabelas para entidades se você precisar gravar dados nessas tabelas. Nesse caso, você traz somente os dados necessários e já coloca em um objeto apropriado. Acho que você está no caminho.

H

Não sei se vc entendeu o que eu quis dizer. Mas esse construtor eu utilizo assim:

Portanto como que eu poderia utilizar 1 único construtor para selecionar apenas os atributos que eu quero em diversas tabelas?

Então, no meu projeto atual eu praticamente não preciso fazer persistência nenhuma. Basicamente só persisto logs. Porém para os próximos projetos eu estava pensando em criar entidades mapeando meu banco de dados automaticamente pelo Netbeans apenas para operações de insert, update e delete. E para as queries envolvendo mais de 1 tabela eu criaria novas entidades simples mapeando seus resultados. Isso funcionaria meio que como uma view (porém acredito que mais eficiente em termos de desempenho).

Tchello

Optaria por escrever uma JPQL/HQL e usar ResultTransformer.
Continua com a vantagem de JPA e a consulta fica light.

H

Tchello:
Optaria por escrever uma JPQL/HQL e usar ResultTransformer.
Continua com a vantagem de JPA e a consulta fica light.

Tchello, esse result transformer é para JPA ou especificamente apenas para o hibernate? Pois estou utilizando o eclipseLink aqui e não consegui encontrar nada sobre ele com result transformer.

Tchello

hfluz:
Tchello:
Optaria por escrever uma JPQL/HQL e usar ResultTransformer.
Continua com a vantagem de JPA e a consulta fica light.

Tchello, esse result transformer é para JPA ou especificamente apenas para o hibernate? Pois estou utilizando o eclipseLink aqui e não consegui encontrar nada sobre ele com result transformer.

Hmm, é do Hibernate:
http://www.jarvana.com/jarvana/view/org/hibernate/hibernate/3.2.2.ga/hibernate-3.2.2.ga-javadoc.jar!/org/hibernate/transform/ResultTransformer.html

Exemplo de uso:
http://pablonobrega.wordpress.com/2010/12/02/usando-resulttransformer-personalizado-na-sua-consulta-com-hibernate/

Abraços.

Criado 27 de outubro de 2011
Ultima resposta 31 de out. de 2011
Respostas 11
Participantes 6