这些实体的equals和hashCode(Spring MVC + Hibernate)
Posted
技术标签:
【中文标题】这些实体的equals和hashCode(Spring MVC + Hibernate)【英文标题】:equals and hashCode of these entities (Spring MVC + Hibernate) 【发布时间】:2014-09-04 09:44:07 【问题描述】:有人可以建议我如何对这些实体执行 equals 和 hashCode 方法吗?
这是 Gara(竞赛)和 Agenzia(代理)之间的多对多关系: 一场比赛有多个机构,一个机构可以参加更多比赛。
我尝试了一些实现,但或者我收到 *** 错误,或者, 当我更新 Gara(竞赛)时,我无法更新一组 Agenzie(代理),因为我收到此错误:
org.springframework.dao.DuplicateKeyException: 一个不同的对象 相同的标识符值已经与会话相关联: [com.myApp.model.GaraAgenzia#com.mmyApp.model.GaraAgenziaId@49f]; 嵌套异常是 org.hibernate.NonUniqueObjectException: a 已关联具有相同标识符值的不同对象 与会议: [com.myApp.model.GaraAgenzia#com.myApp.model.GaraAgenziaId@49f]
当我尝试进行更新时。
谢谢
Gare.java:
@Entity
@Table(name = "gare")
public class Gara extends BaseEntity implements Serializable
private static final long serialVersionUID = 6395640401966812691L;
/*
* inizializzo logger
*/
static Logger logger = LoggerFactory.getLogger(Gara.class);
/*
* molti a molti gara-agenzia
*
* EAGER altrimenti da errore: could not initialize proxy - no Session
*/
@OneToMany(fetch = FetchType.EAGER, mappedBy = "pk.gara", cascade=CascadeType.ALL, orphanRemoval=true)
private Set<GaraAgenzia> garaAgenzie = new HashSet<GaraAgenzia>(0);
/*
* molti a molti gara-servizi
*
* EAGER altrimenti da errore: could not initialize proxy - no Session
*/
@OneToMany(fetch = FetchType.EAGER, mappedBy = "pk.gara", cascade=CascadeType.ALL, orphanRemoval=true)
private Set<GaraServizio> garaServizi = new HashSet<GaraServizio>(0);
/*
*
* colonna TITOLO
*
*/
@NotNull(message = "Il campo TITOLO è obbligatorio")
@NotEmpty(message = "Il campo TITOLO è obbligatorio")
@Size(min = 0, max = 255, message = "Lunghezza massima campo TITOLO: 255 caratteri")
@Column(name = "TITOLO", length = 255)
private String titolo;
/*
*
* colonna OBIETTIVO
*
*/
@NotNull(message = "Il campo OBIETTIVO è obbligatorio")
@Min(value = 1, message = "Il campo OBIETTIVO deve essere maggiore di ZERO")
@Column(name = "OBIETTIVO")
private int obiettivo = 0;
/*
*
* colonna BONUS
*
*/
@NotNull(message = "Il campo BONUS è obbligatorio")
@Min(value = 1, message = "Il campo BONUS deve essere maggiore di UNO")
@Column(name = "BONUS")
private float bonus = 0f;
@Column(name = "data_iniziale", nullable = false)
private Date dataIniziale;
@Column(name = "data_finale", nullable = false)
private Date dataFinale;
public Set<GaraAgenzia> getGaraAgenzie()
return garaAgenzie;
public void setGaraAgenzie(Set<GaraAgenzia> garaAgenzie)
this.garaAgenzie.clear();
this.garaAgenzie = garaAgenzie;
public Set<GaraServizio> getGaraServizi()
return garaServizi;
public void setGaraServizi(Set<GaraServizio> garaServizi)
this.garaServizi.clear();
this.garaServizi = garaServizi;
public void GaraServizio(GaraServizio gara_servizio)
garaServizi.add(gara_servizio);
gara_servizio.setGara(this);
public void removeGaraServizio(GaraServizio gara_servizio)
garaServizi.remove(gara_servizio);
gara_servizio.setGara(null);
public void GaraAgenzia(GaraAgenzia gara_agenzia)
garaAgenzie.add(gara_agenzia);
gara_agenzia.setGara(this);
public void removeGaraAgenzia(GaraAgenzia gara_agenzia)
garaAgenzie.remove(gara_agenzia);
gara_agenzia.setGara(null);
public String getTitolo()
return titolo;
public void setTitolo(String titolo)
this.titolo = titolo;
public int getObiettivo()
return obiettivo;
public void setObiettivo(int obiettivo)
this.obiettivo = obiettivo;
public float getBonus()
return bonus;
public void setBonus(float bonus)
this.bonus = bonus;
public Date getDataIniziale()
return dataIniziale;
public void setDataIniziale(Date dataIniziale)
this.dataIniziale = dataIniziale;
public Date getDataFinale()
return dataFinale;
public void setDataFinale(Date dataFinale)
this.dataFinale = dataFinale;
@Override
public String toString()
return "Gara [garaAgenzie=" + garaAgenzie + ", garaServizi="
+ garaServizi + ", titolo=" + titolo + ", obiettivo="
+ obiettivo + ", bonus=" + bonus + ", dataIniziale="
+ dataIniziale + ", dataFinale=" + dataFinale + "]";
@Override
public int hashCode()
final int prime = 31;
int result = super.hashCode();
result = prime * result + Float.floatToIntBits(bonus);
result = prime * result
+ ((dataFinale == null) ? 0 : dataFinale.hashCode());
result = prime * result
+ ((dataIniziale == null) ? 0 : dataIniziale.hashCode());
result = prime * result + obiettivo;
result = prime * result + ((titolo == null) ? 0 : titolo.hashCode());
return result;
@Override
public boolean equals(Object obj)
if (this == obj)
return true;
if (!super.equals(obj))
return false;
if (getClass() != obj.getClass())
return false;
Gara other = (Gara) obj;
if (Float.floatToIntBits(bonus) != Float.floatToIntBits(other.bonus))
return false;
if (dataFinale == null)
if (other.dataFinale != null)
return false;
else if (!dataFinale.equals(other.dataFinale))
return false;
if (dataIniziale == null)
if (other.dataIniziale != null)
return false;
else if (!dataIniziale.equals(other.dataIniziale))
return false;
if (obiettivo != other.obiettivo)
return false;
if (titolo == null)
if (other.titolo != null)
return false;
else if (!titolo.equals(other.titolo))
return false;
return true;
GaraAgenzia.java:
@Entity
@Table(name = "gare_agenzie")
@AssociationOverrides(
@AssociationOverride(name = "pk.gara",
joinColumns = @JoinColumn(name = "gara_id")),
@AssociationOverride(name = "pk.agenzia",
joinColumns = @JoinColumn(name = "agenzia_id")) )
public class GaraAgenzia implements Serializable
private static final long serialVersionUID = 3865586469933888797L;
/*
* inizializzo logger
*/
static Logger logger = LoggerFactory.getLogger(GaraAgenzia.class);
/*
*
* numero contratti:
*
*
*/
private int numeroContratti = 0;
private GaraAgenziaId pk = new GaraAgenziaId();
@EmbeddedId
public GaraAgenziaId getPk()
return pk;
public void setPk(GaraAgenziaId pk)
this.pk = pk;
@Transient
public Gara getGara()
return getPk().getGara();
public void setGara(Gara gara)
getPk().setGara(gara);
@Transient
public Agenzia getAgenzia()
return getPk().getAgenzia();
public void setAgenzia(Agenzia agenzia)
getPk().setAgenzia(agenzia);
@Column(name = "numero_contratti")
public int getNumeroContratti()
return numeroContratti;
public void setNumeroContratti(int numeroContratti)
this.numeroContratti = numeroContratti;
public boolean equals(Object other)
if (this == other) return true;
if ( !(other instanceof GaraAgenzia) ) return false;
final GaraAgenzia gara_agenzia = (GaraAgenzia) other;
if ( !gara_agenzia.getGara().equals( getGara() ) ) return false;
if ( !gara_agenzia.getAgenzia().equals( getAgenzia() ) ) return false;
return true;
public int hashCode()
int result;
result = getGara().hashCode();
result = 29 * result + getAgenzia().hashCode();
return result;
GaraAgenziaId.java:
@Embeddable
public class GaraAgenziaId implements Serializable
private static final long serialVersionUID = 4934033367128755763L;
/*
* inizializzo logger
*/
static Logger logger = LoggerFactory.getLogger(GaraAgenziaId.class);
private Gara gara;
private Agenzia agenzia;
@ManyToOne
public Gara getGara()
return gara;
public void setGara(Gara gara)
this.gara = gara;
@ManyToOne
public Agenzia getAgenzia()
return agenzia;
public void setAgenzia(Agenzia agenzia)
this.agenzia = agenzia;
/*
* override del metodo di uguaglianza
*/
@Override
public boolean equals(Object o)
if (this == o)
return true;
if (o == null)
return false;
if (o instanceof GaraAgenzia)
final GaraAgenzia other = (GaraAgenzia) o;
return (Objects.equal(getGara().getId(), other.getGara().getId())) && (Objects.equal(getAgenzia().getId(), other.getAgenzia().getId()));
return false;
/*
* override del metodo creazione hashcode
*/
@Override
public int hashCode()
return Objects.hashCode(getGara().getId(), getAgenzia().getId());
/*
public boolean equals(Object other)
if (this == other) return true;
if ( !(other instanceof GaraAgenziaId) ) return false;
final GaraAgenziaId gara_agenzia = (GaraAgenziaId) other;
if ( !gara_agenzia.getGara().equals( getGara() ) ) return false;
if ( !gara_agenzia.getAgenzia().equals( getAgenzia() ) ) return false;
return true;
public int hashCode()
int result;
result = getGara().hashCode();
result = 29 * result + getAgenzia().hashCode();
return result;
*/
/*
@Override
public boolean equals(Object obj)
if (this == obj)
return true;
if (!super.equals(obj))
return false;
if (getClass() != obj.getClass())
return false;
GaraAgenziaId other = (GaraAgenziaId) obj;
if (gara == null)
if (other.gara != null)
return false;
else if (!gara.equals(other.gara))
return false;
if (agenzia == null)
if (other.agenzia != null)
return false;
else if (!agenzia.equals(other.agenzia))
return false;
return true;
*/
编辑 1: 如果我之前清除了一组代理(和服务) 重新设置它:
garaToUpdate.getGaraAgenzie().clear();
garaToUpdate.getGaraServizi().clear();
getCurrentSession().flush();
garaToUpdate.setGaraAgenzie(gara.getGaraAgenzie());
garaToUpdate.setGaraServizi(gara.getGaraServizi());
getCurrentSession().update(garaToUpdate);
我得到这个错误:
不再有 cascade="all-delete-orphan" 的集合 由拥有的实体实例引用:
编辑 2: 正如@JamesB 所建议的,我将 toString 方法添加到 GaraAgenzia 和 GaraAgenziaId。这里是更新 Gara 记录之前的结果:
这是更新前从 db 获取的记录
信息:com.machinet.model.GaraAgenziaId -garaToUpdate.GaraAgenzie (更新前):[GaraAgenzia [numeroContratti=0, pk=GaraAgenziaId [Gara=Gara [titolo=gara 标题,obiettivo=999,奖金=100.00, dataIniziale=2014-07-31, dataFinale=2014-07-31],agenzia=Agenzia(id=1, 名称='Agency 1 ltd', ragione sociale=Agency 1 ltd srl)]]]
这是将在 db 中设置的已编辑记录:
信息:com.machinet.model.GaraAgenziaId - 已编辑Gara.GaraAgenzie (更新前):[GaraAgenzia [numeroContratti=0, pk=GaraAgenziaId [Gara=Gara [titolo=gara 标题,obiettivo=999,奖金=100.00, dataIniziale=2014-07-31, dataFinale=2014-07-31],agenzia=Agenzia(id=1, 名称='Agency 1 ltd', ragione sociale=Agency 1 ltd srl]]]
【问题讨论】:
您是否在保存更新前调试了 Gare#garaAgenzie 的内容? 我在将 Gara 添加到 Db 时分配了一组 GareAgenzia:每条记录都有“numeroContatti”(附加字段)和“pk”(这是 id 实体) 你检查过每个人的ID吗? ID 是指嵌入式 ID。 db中的id是一样的,但是括号之间的id(我认为是编译器生成的)不同 如果数据库中的 ID 相同,那么您在 Set 中有相同的实体,这是不允许的,因此会出现 DuplicateKeyException。 【参考方案1】:这些似乎运作良好。我发帖希望有人会觉得它有用:
GaraAgenzia 类:
public boolean equals(Object o)
if (this== o) return true;
if (o ==null|| getClass() != o.getClass()) return false;
GaraAgenzia that = (GaraAgenzia) o;
if (getPk() !=null?!getPk().equals(that.getPk()) : that.getPk() !=null) return false;
return true;
public int hashCode()
return (getPk() !=null? getPk().hashCode() : 0);
GaraAgenziaId 类:
public boolean equals(Object o)
if (this== o) return true;
if (o ==null|| getClass() != o.getClass()) return false;
GaraAgenziaId that = (GaraAgenziaId) o;
if (gara !=null?!gara.equals(that.gara) : that.gara !=null) return false;
if (agenzia !=null?!agenzia.equals(that.agenzia) : that.agenzia !=null)
return false;
return true;
public int hashCode()
int result;
result = (agenzia !=null? agenzia.hashCode() : 0);
result =31* result + (gara !=null? gara.hashCode() : 0);
return result;
【讨论】:
不知道它是否是有意的,但如果this.pk
和that.pk
都是null
,GaraAgenzia
中的equals
将返回true
。 Vlad Mihalcea 建议做一个更简单的return id != null && this.id.equals(that.id);
hashcode
还必须根据其合同返回一个常量值(也由 hibernate 文档推荐),因此返回一个常量或散列一些永远不会改变的属性。 Mihalcea 的博客:vladmihalcea.com/… 另外,请参阅 hibernate 文档中 Implementing equals() and hashCode()
的结尾。【参考方案2】:
这不是一个确切的答案,但可能会帮助遇到类似问题的人。我创建了一个由所有实体扩展的抽象类。这样我就不需要在所有实体中实现这些方法了。
public abstract class GenericEntity implements Serializable
protected static final long serialVersionUID = 1L;
abstract public Serializable getId();
@Override
public int hashCode()
return (getId() == null) ? System.identityHashCode(this) : getId().hashCode();
@Override
public boolean equals(Object obj)
if (this == obj)
return true;
if (obj == null)
return false;
if (this.getClass() != obj.getClass())
return false;
if (org.hibernate.Hibernate.getClass(this) != org.hibernate.Hibernate.getClass(obj))
return false;
GenericEntity other = (GenericEntity) obj;
if (getId() == null || other.getId() == null)
return false;
return getId().equals(other.getId());
我认为在你的情况下你可以把它放在你的 BaseEntity 中。
【讨论】:
以上是关于这些实体的equals和hashCode(Spring MVC + Hibernate)的主要内容,如果未能解决你的问题,请参考以下文章
我应该在 JPA 实体中编写 equals() 和 hashCode() 方法吗?
@Transient 属性应该用在 equals/hashCode/toString 中吗?
Hibernate:我是不是应该在 hashcode() 和 equals() 方法中包含“版本”字段
java 集合中重写hashCode方法和重写equals方法啥关系?