Como o equals e o hashcode da classe do modelo devem ser implementados no Hibernate? Quais são as armadilhas comuns? A implementação padrão é boa o suficiente para a maioria dos casos? Há algum sentido em usar chaves comerciais?
Parece-me muito difícil fazer funcionar corretamente em todas as situações, quando o lazy fetching, geração de id, proxy, etc. são levados em consideração.
Respostas:
O Hibernate tem uma boa e longa descrição de quando / como substituir
equals()
/hashCode()
na documentaçãoA essência disso é que você só precisa se preocupar se sua entidade fará parte de um
Set
ou se você for desanexar / anexar suas instâncias. Este último não é tão comum. O primeiro geralmente é mais bem tratado por meio de:equals()
/hashCode()
em uma chave de negócios - por exemplo, uma combinação única de atributos que não vai mudar durante a vida útil do objeto (ou, pelo menos, da sessão).equals()
/hashCode()
na chave primária SE estiver definida e na identidade do objeto /System.identityHashCode()
caso contrário. A parte importante aqui é que você precisa recarregar seu Set após a nova entidade ter sido adicionada a ele e persistida; caso contrário, você pode acabar com um comportamento estranho (em última análise, resultando em erros e / ou corrupção de dados) porque sua entidade pode ser alocada para um intervalo que não corresponde ao seu atualhashCode()
.fonte
refresh()
? Como sua entidade, que obedece aoSet
contrato, acaba no balde errado (supondo que você tenha uma implementação de hashcode boa o suficiente).Set.contains(entity)
e você retornaráfalse
. O mesmo vale para get () / put () / etc ...Não acho que a resposta aceita seja correta.
Para responder à pergunta original:
A resposta é sim, na maioria dos casos é.
Você só precisa substituir
equals()
ehashcode()
se a entidade for usada em umSet
(o que é muito comum) E a entidade será desanexada e posteriormente reconectada às sessões de hibernação (que é um uso incomum de hibernação).A resposta aceita indica que os métodos precisam ser substituídos se qualquer uma das condições for verdadeira.
fonte
A melhor
equals
/hashCode
implementação é quando você usa uma chave comercial exclusiva .A chave de negócios deve ser consistente em todas as transições de estado da entidade (transiente, anexado, desanexado, removido), é por isso que você não pode contar com id para igualdade.
Outra opção é passar a usar identificadores UUID , atribuídos pela lógica do aplicativo. Dessa forma, você pode usar o UUID para o
equals
/hashCode
porque o id é atribuído antes que a entidade seja liberada.Você pode até usar o identificador de entidade para
equals
ehashCode
, mas isso exige que você sempre retorne o mesmohashCode
valor para que você tenha certeza de que o valor hashCode da entidade é consistente em todas as transições de estado da entidade. Confira esta postagem para mais informações sobre este tópico .fonte
BaseEntity
e nunca mais pense sobre esse problema. É preciso um pouco de espaço do lado do banco de dados, mas é melhor pagar esse preço pelo conforto :)Quando uma entidade é carregada por meio de carregamento lento, não é uma instância do tipo base, mas é um subtipo gerado dinamicamente gerado por javassist, portanto, uma verificação no mesmo tipo de classe falhará, portanto, não use:
em vez disso, use:
que também é uma boa prática, conforme explicado em Implementando equals no Java Practices .
pelo mesmo motivo, acessar diretamente os campos pode não funcionar e retornar nulo, em vez do valor subjacente, portanto, não use a comparação nas propriedades, mas use os getters, pois eles podem disparar para carregar os valores subjacentes.
fonte
Sim, é difícil. Em meu projeto, equals e hashCode contam com o id do objeto. O problema dessa solução é que nenhuma delas funciona se o objeto ainda não foi persistido, pois o id é gerado pelo banco de dados. No meu caso, isso é tolerável, pois em quase todos os casos os objetos são persistidos imediatamente. Fora isso, funciona muito bem e é fácil de implementar.
fonte
Na documentação do Hibernate 5.2 diz que você pode não querer implementar hashCode e equals - 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 da mesma sessão serão iguais se forem iguais no banco de dados (sem implementar hashCode e equals).
Fica complicado se você estiver usando duas ou mais sessões. Nesse caso, a igualdade de dois objetos depende da implementação do método igual.
Além disso, você terá problemas se seu método equals estiver comparando IDs que são gerados apenas durante a persistência de um objeto pela primeira vez. Eles podem não estar lá ainda quando igual é chamado.
fonte
Há um artigo muito bom aqui: https://docs.jboss.org/hibernate/stable/core.old/reference/en/html/persistent-classes-equalshashcode.html
Citando uma linha importante do artigo:
Em termos simples
fonte
Se acontecer de você substituir
equals
, certifique-se de cumprir seus contratos: -E substituir
hashCode
, já que seu contrato depende daequals
implementação.Joshua Bloch (designer do framework Collection) recomendou enfaticamente que essas regras fossem seguidas.
Existem efeitos não intencionais graves quando você não segue esses contratos. Por exemplo,
List#contains(Object o)
pode retornar umboolean
valor incorreto porque o contrato geral não foi cumprido.fonte