Qual a importancia de se utilizar JPA ao invés de Hibernate?

Ótimo tópico, não vejo grandes diferenças não, como já falado anteriormente acho bacana a Sun trazer algo de sucesso para especificação…

A JPA por se tratar de uma abstração que funciona independente de uma implementação específica te permite
ter alternativas ao Hibernate(claro que a implementação dele é a melhor entre outras), te possibilitando uma flexibilidade de escolha, acho isto um quesito muito importante quando se trabalha com boas práticas de OO…

Como já falado, outro obstaculo a JPA seria o Criteria, mas já foi inserido na especificação 2.0 com alguns recursos de tipagem não existentes no Hibernate…

Rogel deixa de ser chato e teimoso e usa o JPA… :smiley:

Hahahah… blza Breno…

Só estou estressando as possibilidades para ver qual é a melhor alternativa…

Se vou usar alguma coisa… tenho que ter motivos para isso… to procurando os motivos…

Não gosto de usar alguma coisa só pq um povo que nem programa no dia a dia definiu… (já vi muitas definicoes ruins desse pessoal)

Vejamos esse mapeamento (eliminei os getters e setters para simplificar):

@Entity
public class Produto {

	@Id
	@GeneratedValue(strategy=SEQUENCE, generator="sq_produto")
	@SequenceGenerator(name="sq_produto", sequenceName="sq_produto")
	Integer id;
	String nome;
	@ManyToOne(fetch=FetchType.LAZY)
	Tipo tipo;
	

Isso poderia ser feito assim:

public class Produto {

	Integer id;
	String nome;
	Tipo tipo;
	

Todas as informações do mapeamento já estão na classe…
Eu poderia configurar no meu persistence.xml
Todos as classes do pacote com.company.persistence são entidades
Os atributos com nome id são @Id
Todos os @id devem usar um sequence com nome sq_{nomedaclasse}
É óbvio que Tipo é um @ManyToOne… e poderia definir que todos os @ManyToOne são lazy

Pronto… eu configuraria meu padrão uma vez na minha app… e não precisaria lotar minha classe com anotations… isso sim… é uma coisa prática… que ajuda no sistema e diminui o acoplamento

Agora o povo fica só pensando em coisas do reino da imaginacao que no dia a dia nem tem tanta importancia

Lavieri

poderia explicar melhor esta estrutura:

pelo que eu entendi queries é uma classe onde vc pode pegar objetos de consulta especificos de cada classe do mdoelo, no caso o forPessoa retorna um desses objetos pra classe Pessoa. nesses objetos estão as queries especificas de pessoas, como no exemplo listPessoasAtivas. só não entendi o que esse query on retorna, acho que é um obejto que sabe qual query a ser executada no repositório, mas não estou com certeza disso.

Achei muito bacana, quero entender pra montar algo do tipo.

[]'s

Outra coisa…

Imagine que eu tenho a classe Mestre e a classe mestre tenha uma List de Detalhe

[code]class Mestre {

 List<Detalhe> detalhes;

}[/code]

Se eu anotar os detalhes com aqueles cascades todos… pra ficar tudo automático…

Como eu faço se eu quiser alterar só o Mestre e não quiser mecher nos Detalhes? Se eu mandar persistir o Mestre sem Detalhe nenhum (lista vazia)… o JPA/Hibernate vai apagar todos os meus detalhes…

[quote=rogelgarcia]Outra coisa…

Imagine que eu tenho a classe Mestre e a classe mestre tenha uma List de Detalhe

[code]class Mestre {

 List<Detalhe> detalhes;

}[/code]

Se eu anotar os detalhes com aqueles cascades todos… pra ficar tudo automático…

Como eu faço se eu quiser alterar só o Mestre e não quiser mecher nos Detalhes? Se eu mandar persistir o Mestre sem Detalhe nenhum (lista vazia)… o JPA/Hibernate vai apagar todos os meus detalhes…[/quote]

Bom, com o que vc tem hj tem como fazer apenas de forma estática, insertable = false …

[quote=rogelgarcia]Outra coisa…

Imagine que eu tenho a classe Mestre e a classe mestre tenha uma List de Detalhe

[code]class Mestre {

 List<Detalhe> detalhes;

}[/code]

Se eu anotar os detalhes com aqueles cascades todos… pra ficar tudo automático…

Como eu faço se eu quiser alterar só o Mestre e não quiser mecher nos Detalhes? Se eu mandar persistir o Mestre sem Detalhe nenhum (lista vazia)… o JPA/Hibernate vai apagar todos os meus detalhes…[/quote]

Não entendi o cenário. Pq detalhes esta vazio? Ele poderia estar com o proxy Lazy de sua representação no banco, e vc alterar os outros atributos de Mestre normalmente. Uma coisa não tem haver com outra.

Eu poderia estar com um Mestre desatachado da sessao… que eu quisesse persistir… (mas a lista de Detalhe está vazia)

Eu gostaria de só alterar o Mestre… mas se eu pedir pra salvar o Mestre desse jeito… o hibernate também deleta o detalhe…

Tem vários motivos para vc iniciar um projeto com JPA, a maioria já foi explanado aqui, mas vamos lá:

  • Bootstrap facilitado: HibernateUtil é um “workaround” necessário para se construir a SessionFactory. Já vi muita implementação meia boca estourando memória por causa disso. O JPA em ambiente JavaEE é bem mais eficiente em sua inicialização com o apoio do persistence.xml, autodiscovery das classes anotadas e gerencia do EntityManager feita automaticamente pelo container (abri, fechar, descarregar e injetar).

  • D.I. - Uma vez fazendo parte da especificação, ele se beneficia de todos os demais recursos enterprises, sobre injeção de dependencia e todo seu ciclo de vida. No JavaEE 6, isso esta ainda melhor, uma vez que não apenas EJBs podem se beneficiarem com isso, mas qualquer bean.

  • Portabilidade (menos relevante) - nao considero isso a melhor feature para iniciar um projeto com JPA, pq EU utilizao muita coisa do Hibernate. Mas para quem preza por independecia de implementação pode ser um atrativo.

O fato é, 99,9% das vezes inicio os projetos com JPA. Quando algo nao me atende entao getDelegate para obter a session do hibernate, sem pestanejar. Mas nao perco a integração com o ambiente JavaEE e nem seu bootstrap que é uma mao na roda.

[quote=rogelgarcia]Eu poderia estar com um Mestre desatachado da sessao… que eu quisesse persistir… (mas a lista de Detalhe está vazia)

Eu gostaria de só alterar o Mestre… mas se eu pedir pra salvar o Mestre desse jeito… o hibernate também deleta o detalhe…[/quote]

Mas “PQ” detalhe esta vazia???
Se Mestre esta detachado e vc faz “Merge”, ele nao apaga sua lista, ele relinka os proxies de Detalhe, que NAO esta vazio.
A não ser que vc tenha construído o Mestre com “new”, o que nao deveria ser feito.

[quote=mario.fts]Lavieri

poderia explicar melhor esta estrutura:

pelo que eu entendi queries é uma classe onde vc pode pegar objetos de consulta especificos de cada classe do mdoelo, no caso o forPessoa retorna um desses objetos pra classe Pessoa. nesses objetos estão as queries especificas de pessoas, como no exemplo listPessoasAtivas. só não entendi o que esse query on retorna, acho que é um obejto que sabe qual query a ser executada no repositório, mas não estou com certeza disso.

Achei muito bacana, quero entender pra montar algo do tipo.

[]'s[/quote]

queries e’ uma fachada… ele conhece os caminhso para os objetos que conhece a query de cada entidade…

public class Queries { public PessoaQuery forPessoa() { return PessoaQuery.getInstance(); } public ImovelQuery forImovel() { return ImovelQuery.getInstance(); } } //ou seja apenas uma facahada.....

PessoaQuery contem todas as querys para pessoas

[code]
public class PessoaQuery {
public QueryableList listarAtivas() {
DatechedCriteria dc = DatechedCriteria.forClass(Pessoa.class)
.add(Restrictions.eq(“ativo”,true);
return new HibernateQuery(dc).list();
}

 public Queryable<Pessoa> byCpf(String cpf) {
       //...
       return new HibernateQuery<Pessoa>(dc).unique();
 }

}[/code]

QueryableList e’ uma interface

[code]

public Queryable {
T queryOn(Repository rep);
}

public QueryableList extends Queryable<List> {
List queryOn(Repository rep,int startPosition);
List queryOn(Repository rep,int startPosition,int maxResults);
}[/code]

HiberanteQuery e’ uma classe que retorna Queryable ou QueryableList

public HiberanteQuery<T> { public HiberanteQuery<T>(DetachedCriteria dc) {this.dc = dc} Queryable<T> unique(); Queryable<T> first(); Queryable<Integer> count(); QueryableList<T> list(); }

a implementacao desses metados e’ juntar a session do Repository com a DatechedCriteria que e’ passado no construtor.

e assim retorna a consulta tipada que esta definida no queryable ou queryablelist

Muito bom cara, vou montar um esquema assim pra testar.

Valeu.

[quote=rogelgarcia]Com a nova (nem tão nova assim) onda de se utilizar JPA ao invés de Hibernate, surgem as questões…

Quase todo mundo que hoje utiliza JPA, tem como implementação o Hibernate que já utilizavam anteriormente…

O JPA introduziu novas interfaces e classes além do que já tinhamos que saber com o Hibernate. Mas o JPA não é uma especificação completa porque ainda é necessário em alguns momentos utilizar coisas especificas do Hibernate.

O JPA acabou introduzindo uma nova camada de persistencia e nós sabemos que camadas em cima de camadas trazem problemas.

Se a implementação de JPA que todo mundo utiliza é o Hibernate, qual é a utilidade de se ter JPA?[/quote]

Nenhuma. A utilidade do JPA é nenhuma.
Depois que o pessoal do Core Patterns JEE levou na cabeça , e depois que o Hibernate foi criado foi desenvolvido o padrão DomainStore.
É este padrão que o JPA tenta implementar.
O JPA nasceu como uma alternativa OO ao JDBC mas ao contrario deste ele nasceu falho. O conceito de Native Query é completamente idiota
porque mata o objetivo de ter um mecanismo portável entre bancos. Da mesma forma que o JDBC precisa de um mecanismo para o adquar a vários bancos o JPA precisa do mesmo. O Hibernate não precisa.

O sucesso do hibernate se deve ao padrão DomainStore e ao fato de ser free. Hoje em dias temos opções como Eclipse Link, mas aprender a usar mais uma ferramenta ORM é chato p’rá caramba.

Usar o JPA é na realidade um erro no contexto geral e só justificavel se vc quiser aderir às normas de portabilidade JEE, que todo o mundo já sabe são falhas em si mesmas.

É um falso argumento que precisamos do JPA para isolar o hibernate. Isso é feito facilmente com objetos criados por nós mesmos usando padrões como bridge e strategy. Eu nunca usaria JPA por escolha.

[quote=Lavieri]eu iniciei lendo no blog do sergio taborda http://sergiotaborda.wordpress.com/desenvolvimento-de-software/java/patterns/repository/

depois fui fazendo a minha maneira…

A entender, a diferenca basica do DAO pro RESPOSITORIO, e’ que o DAO acumla as queries dentro dele, e por isso vc sai criando 1 DAO por Entidade… isso traz dificuldade, pois uma Session funciona com um repositorio, ela funciona igual seja a entidade qual for…

Entao o repositorio tem aceita objetos em seus metodos, e asism repository.add(Object o); e assim para cada operacao,

Tudo que for generico vc deixa no repositorio, ou seja

<T> List<T> repo.list(Class<T> target);
<T> T repo.get(Class<T> target, Object id);
repo.refresh(Object object);

etc etc etc

e as queries as consultas, vc separa coloca em outro objeto, eu crirei uma interface pra fazer isso…

e no fim, eu executo uma Query em um Repository,

que para o hiberante eu so faco pegar um DatechedCriteria que esta dentro do queries, e unir a session dentro do repository, e assim a magica da consulta acontece…[/quote]

Incrível, mas eu quiz dizer exatamente o contrário do que vc entendeu.
O Repositório não é genérico nem agnóstico, ele é concreto e associado a uma única entidade. O repositório cria as queries, ele não executa as queries.
Cada repositorio especifico contém métodos para encontrar aquele tipo de entidade, conforme critérios que fazem sentido para ela. Pode conter métodos gerais comuns a todas as entidades como save e delete, mas fortemente tipados para aceitar apenas aquele tipo de entidade. nisto os repositorios em nada são diferentes dos antigos DAO.

A diferença entre DAO e Repositório é que o DAO é um tradutor de tecnologias (ORM, OXM, etc…) Repositório é um encapsulador de regras de pesquisas e um ponto centrar para procurar objetos daquela entidade.

vou ter que mehlorar esse artigo :oops: …

[quote=Alessandro Lazarotti]Tem vários motivos para vc iniciar um projeto com JPA, a maioria já foi explanado aqui, mas vamos lá:

  • Bootstrap facilitado: HibernateUtil é um “workaround” necessário para se construir a SessionFactory. Já vi muita implementação meia boca estourando memória por causa disso. O JPA em ambiente JavaEE é bem mais eficiente em sua inicialização com o apoio do persistence.xml, autodiscovery das classes anotadas e gerencia do EntityManager feita automaticamente pelo container (abri, fechar, descarregar e injetar).

  • D.I. - Uma vez fazendo parte da especificação, ele se beneficia de todos os demais recursos enterprises, sobre injeção de dependencia e todo seu ciclo de vida. No JavaEE 6, isso esta ainda melhor, uma vez que não apenas EJBs podem se beneficiarem com isso, mas qualquer bean.

  • Portabilidade (menos relevante) - nao considero isso a melhor feature para iniciar um projeto com JPA, pq EU utilizao muita coisa do Hibernate. Mas para quem preza por independecia de implementação pode ser um atrativo.

O fato é, 99,9% das vezes inicio os projetos com JPA. Quando algo nao me atende entao getDelegate para obter a session do hibernate, sem pestanejar. Mas nao perco a integração com o ambiente JavaEE e nem seu bootstrap que é uma mao na roda.

[/quote]

Pois então… tudo isso que voce falou aí … chegou atrasado… já existem essas features a 5 anos no framework que eu criei :smiley:

Pros projetos que eu uso então… nao teria vantagem… a nao ser a questao de portabilidade que é o menos importante…

E se eu quiser usar o JPA no desktop… é trivial?

[quote=Alessandro Lazarotti][quote=rogelgarcia]Eu poderia estar com um Mestre desatachado da sessao… que eu quisesse persistir… (mas a lista de Detalhe está vazia)

Eu gostaria de só alterar o Mestre… mas se eu pedir pra salvar o Mestre desse jeito… o hibernate também deleta o detalhe…[/quote]

Mas “PQ” detalhe esta vazia???
Se Mestre esta detachado e vc faz “Merge”, ele nao apaga sua lista, ele relinka os proxies de Detalhe, que NAO esta vazio.
A não ser que vc tenha construído o Mestre com “new”, o que nao deveria ser feito.[/quote]

A parte controller da minha app… pode ter criado o Mestre… entao será com new por exemplo

[quote=Lavieri]j

[code]repository.addAll(carros);
repoistory.removeAll(telefones);

List<PessoaFisica> pessoasAtivas = queries.forPessoa().listPessoasAtivas().queryOn(repository);
[/code]
[/quote]

Isto que vc desenhou não é um repositorio é um DAO. Repositorios são usados assim


Repositorio&lt;Pessoa&gt; rep = ...

List&lt;Pessoa&gt; pessoasAtivas = rep.listPessoasAtivas();

O codigo não sabe qual é o critério que define que a pessoa é ativa. Nem sabe como procurar essa especie de pessoas

Dentro do Repositorio vc tem isto


public List&lt;Pessoa&gt; listPessoasAtivas(){

        Criteria c = CriteriaBuilder.find(Pessoa.class)
                          with("ativo", true);

        return persistanceStategy.executeCriteria(c)

}

Repare que o query é em cima da persistanceStategy. Que pode ser um DAO ou domainStore

O importante aqui é que a criação do critério de busca é no proprio repositório. É essa a sua principal função : encapsular a criação dos critérios.

[quote=sergiotaborda]…

O codigo não sabe qual é o critério que define que a pessoa é ativa. Nem sabe como procurar essa especie de pessoas

Dentro do Repositorio vc tem isto


public List&lt;Pessoa&gt; listPessoasAtivas(){

        Criteria c = CriteriaBuilder.find(Pessoa.class)
                          with("ativo", true);

        return persistanceStategy.executeCriteria(c)

}

Repare que o query é em cima da persistanceStategy. Que pode ser um DAO ou domainStore

O importante aqui é que a criação do critério de busca é no proprio repositório. É essa a sua principal função : encapsular a criação dos critérios.
[/quote]

Bom o nome pode não ser esse… masss o que eu não gosto do DAO é justamente o fato de ser tipado, e de ter as queries dentro dele, ter que usar 192382938 lugares para adicionar e remover entidades é o ponto onde não gosto… e pra mim isso é dar um passo pra traz.

O Hiberante aceita qualquer objeto em suas sessions, e vc encapsular a session e restringir isso pra mim é tiro no pé.

O meu repositorio, é realmente o que diz o nome, é um lugar onde se guarda onde se armazena as entidades, é possivel adicionar, remover, atualizar buscar entidades dentro dele.

O queries faz parte da camada de persistencia, e vem justamente para não ter q existir 10928239289 repositorios e existir apenas 1, o único objetivo é desassociar as consultas do repositorio e assim não ter q existir vários locais, ou seja, varios repositorios.

queries.forPessoa().listPessoasAtivas().queryOn(repository);

é apenas pq é muito mais legal 1 repositorio, um único lugar

do que ter

repoPessoa.listPessoasAtivas();
repoCarro.listCarrosByAno(2005);
repoEtc.procureEtcPorCriterioX(x);

enfim isso é xato, é extremamente chato!

repository.forPessoas().listPessoasAtivas(); poderia ate ser… mais ai eu tenho que juntar ao repository, e meu repositorio independe de projeto.

enfim, o conceito que vc viu pode ate ser de ser tudo junto, mas desassociar me da mais flexibilidade, e não tenho intenção de abrir mão disso ^^

[quote=mario.fts]Muito bom cara, vou montar um esquema assim pra testar.

Valeu.[/quote]

ahhh

eu também tenho objetos Executables, que é uma interface e tem apenas o método para executar

public interface Executable { int executeOn(Repository repo); }

serve para algo como

[quote=rogelgarcia][quote=Alessandro Lazarotti][quote=rogelgarcia]Eu poderia estar com um Mestre desatachado da sessao… que eu quisesse persistir… (mas a lista de Detalhe está vazia)

Eu gostaria de só alterar o Mestre… mas se eu pedir pra salvar o Mestre desse jeito… o hibernate também deleta o detalhe…[/quote]

Mas “PQ” detalhe esta vazia???
Se Mestre esta detachado e vc faz “Merge”, ele nao apaga sua lista, ele relinka os proxies de Detalhe, que NAO esta vazio.
A não ser que vc tenha construído o Mestre com “new”, o que nao deveria ser feito.[/quote]

A parte controller da minha app… pode ter criado o Mestre… entao será com new por exemplo[/quote]

Será como não, SERA de fato um new. Se o seu controller criou o Mestre, e não buscou do banco, então é um novo Mestre, o detalhe obivamente é vazio e faz sentido que seja - o estado do objeto é transiente. Se você quer ter uma referência ao banco sem ter problema de reescrita em um campo que vc nao esta utilizando, utilize “getReference” em vez de “find”. Ele passa seu objeto ao estado persistent, sem carregar nada, nem mesmo ir ao banco, apenas adiciona proxies. Como vc quer apenas setar uma propriedade, essa seria a escolha correta (sem entrar no mérito do batch update).