Pergunta

Como deve modelar iguais de classe e hashcode ser implementado em hibernação? Quais são as armadilhas comuns? É o suficiente padrão implementação boa para a maioria dos casos? Existe algum sentido para usar teclas de negócios?

Parece-me que é muito difícil obtê-lo direito ao trabalho em cada situação, quando busca preguiçosa, geração de id, proxy, etc são levados em conta.

Foi útil?

Solução

O Hibernate tem um bom e longo descrição de quando / como substituir equals() / hashCode() em documentação

A essência do que é que você só precisa se preocupar com isso se a sua entidade será parte de um Set ou se você estiver indo para retirar / colocar suas instâncias. Este último não é tão comum. O primeiro é geralmente melhor tratada através de:

  1. Basing equals() / hashCode() em uma chave de negócios - por exemplo, uma combinação única de atributos que não vai mudar durante o objeto (ou, pelo menos, sessão) vida.
  2. Se o acima é impossível, equals() base / hashCode() na chave primária se é conjunto e objeto identidade / System.identityHashCode() contrário. O importante parte aqui é que você precisa Recarregar o seu Set após nova entidade foi adicionado a ele e persistiu; caso contrário você pode acabar com um comportamento estranho (resultando em erros e / ou corrupção de dados) porque a sua entidade pode ser imputados a um balde que não corresponde a sua hashCode() atual.

Outras dicas

Eu não acho que a resposta aceita é preciso.

Para responder à pergunta original:

tem boa o suficiente implementação padrão para a maioria dos casos?

A resposta é sim, na maioria dos casos é.

Você só precisa equals() override e hashcode() se a entidade será usado em um Set (que é muito comum) E a entidade vai ser separada e, posteriormente, re-conectado, hibernate sessões (que é um uso incomum de hibernação).

A resposta aceita indica que os métodos precisam ser anulado se qualquer condição é verdadeira.

Quando uma entidade é carregado através de carregamento lento, não é uma instância do tipo base, mas é um subtipo gerado dinamicamente gerado pelo Javassist, assim, um cheque no mesmo tipo de classe irá falhar, então não use:

if (getClass() != that.getClass()) return false;

utilizar:

if (!(otherObject instanceof Unit)) return false;

que também é uma boa prática, como explicado na Implementação iguais em Práticas de Java .

pela mesma razão, acessando diretamente campos, pode não funcionar e nulo retorno, em vez do valor subjacente, portanto, não use a comparação das propriedades, mas usar os getters, uma vez que pode desencadear para carregar os valores subjacentes.

A melhor implementação equals / hashCode é quando você usa um chave única de negócios .

A chave de negócios deve ser consistente em todos estado entidade transições (transitória, anexado, individual, removido), é por isso que você não pode confiar em id para a igualdade.

Outra opção é mudar para usando UUID identificadores , atribuído pelo aplicativo lógica. Dessa forma, você pode usar o UUID para o equals / hashCode porque o ID é atribuído antes de a entidade é liberada.

Você ainda pode usar o identificador de entidade para equals e hashCode, mas que exige que você retornar sempre o mesmo valor hashCode para que você se certificar de que o valor entidade hashCode é consistente em todas as transições de estado entidade. Confira este post para saber mais sobre este tema .

Sim, é difícil. No meu projeto iguais e hashCode ambos contam com o id do objeto. O problema desta solução é que nenhum deles funciona se o objeto não foi persistiu, no entanto, como o ID é gerado pelo banco de dados. No meu caso que é tolerável uma vez que em quase todos os casos os objetos são persistentes imediatamente. Fora isso, ele funciona muito bem e é fácil de implementar.

Se você passou a substituir equals, certifique-se de cumprir os seus contratos: -

  • SYMMETRY
  • REFLEXIVA
  • transitivo
  • CONSISTENTE
  • Não NULL

E hashCode override, como seu contrato dependem de implementação equals.

Joshua Bloch (designer de quadro Collection) instou veementemente estas regras a serem seguidas.

  • ponto 9: Sempre substituir hashCode quando você substituir iguais

Existem efeito não intencional sério quando você não seguir esses contratos. Por exemplo List.contains(Object o) pode retornar valor boolean errado como o contrato geral não cumpridas.

Na documentação do Hibernate 5.2 ele diz que você não pode querer implementar hashCode e iguais em tudo -. Dependendo da sua situação

https: // docs.jboss.org/hibernate/orm/5.2/userguide/html_single/Hibernate_User_Guide.html#mapping-model-pojo-equalshashcode

Geralmente, dois objetos carregados a partir da mesma sessão será igual se eles são iguais no banco de dados (sem implementar hashCode e igual).

Fica complicado se você estiver usando duas ou mais sessões. Neste caso, a igualdade de dois objetos depende de sua implementação equals-método.

Além disso, você vai ter problemas se o seu equals-método é comparar IDs que só são gerados enquanto persistir um objeto pela primeira vez. Eles podem não estar lá mas quando iguais é chamado.

Não é muito bom artigo aqui: https://docs.jboss.org/hibernate/stable/core.old/reference/en/html/persistent-classes-equalshashcode.html

Citando uma importante linha do artigo:

Recomendamos iguais de execução () e hashCode () usando a chave do negócio igualdade. -chave de negócios significa igualdade que o método () é igual a compara apenas as propriedades que formam a chave de negócios, uma chave que identificaria nossa instância no mundo real (um candidato natural chave):

Em termos simples

public class Cat {

...
public boolean equals(Object other) {
    //Basic test / class cast
    return this.catId==other.catId;
}

public int hashCode() {
    int result;

    return 3*this.catId; //any primenumber 
}

}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top