我有一个名为Employee的表,它有一个复杂的主键,即其列中的3个
的组合firstName : String
SecondName : String
bossId : foreingKey of other table named Boss ( auto generated database sequence)
这是我的代码:
@Entity
@Table(name = "Employee")
@org.hibernate.annotations.Entity(optimisticLock = OptimisticLockType.ALL, dynamicUpdate = true)
public class Employee {
private EmployeePk employeePk;
private int age;
private String status;
@EmbeddedId
public EmployeePk getEmployeePk() {
return employeePk;
}
public void setEmployeePk(EmployeePk employeePk) {
this.employeePk = employeePk;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null ||
!(o instanceof Employee)) {
return false;
}
Employee other
= (Employee)o;
// if the id is missing, return false
if (getEmployeePk() == null) return false;
if( getEmployeePk().equals(other.getEmployeePk())) {
return true;
} else {
return false;
}
}
@Override
public int hashCode() {
if (getEmployeePk() != null) {
return getEmployeePk().hashCode();
} else {
return super.hashCode();
}
}
}
@Embeddable
public class EmployeePk implements Serializable{
private static final long serialVersionUID = -7827123517392541880L;
private String firstName;
private String secondName;
private Boss boss;
@ManyToOne
@JoinColumn(name = "boss_id",insertable= false, updatable= false)
public Boss getBoss() {
return boss;
}
public void setBoss(
Boss boss) {
this.boss = boss;
}
/* setters and getters of all with @column annotation */
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof EmployeePk)) {
return false;
}
EmployeePk other = (EmployeePk) obj;
if( getfirstname() != null &&
getFirstName().equals(other.getFirstName()) &&
getSecondName() !=null &&
getSecondName().equals(other.getSecondName()) &&
getBoss() != null &&
getBoss().getId() == other.getBoss().getId())
return true;
return false;
}
@Override
public int hashCode() {
if (getFirstName() != null &&
getSecondName() != null &&
getBoss() != null) {
return getFirstName().hashCode() +
getSecondName().hashCode();
} else {
return super.hashCode();
}
}
}
现在,一切运行正常,我可以在Employee表中创建/更新/删除数据库行。
但是当我尝试在一个单独的事务中更新相同的行时,我得到了这个例外:
org.hibernate.event.def.AbstractFlushingEventLis
tener: Could not synchronize database state with session
org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect):
at org.hibernate.persister.entity.AbstractEntityPersister.check(AbstractEntityPersister.java:1792)
at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2435)
at org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:2335)
at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2635)
at org.hibernate.action.EntityUpdateAction.execute(EntityUpdateAction.java:115)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:279)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:263)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:168)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
at org.hibernate.event.def.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:64)
at org.hibernate.impl.SessionImpl.autoFlushIfRequired(SessionImpl.java:996)
at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1141)
at org.hibernate.impl.QueryImpl.list(QueryImpl.java:102)
at org.hibernate.impl.AbstractQueryImpl.uniqueResult(AbstractQueryImpl.java:835)
我与另一个名为Contractor的表有类似的问题但是能够通过覆盖它的equals和hashCode方法来解决这个问题。
问题是在那个表中只有一个名为“id”的主键是一个数据库自动生成的序列,因此
那里没有EmbeddedId
的概念。
我不确定我在哪里出错了。我花了几天时间来解决这个问题并遵循了几个链接,例如:http://onjava.com/pub/a/onjava/2006/09/13/dont-let-hibernate-steal-your-identity.html?page=1
答案 0 :(得分:0)
有几点想法:
1)使用optimisticLock = OptimisticLockType.ALL让我怀疑。我自己从未使用过这个,但我怀疑它可能与你的错误有关。
2)我不认为equals方法处理任何属性为null的情况。即使两个实例都相同,它也总是返回false。
3)当你使用专用id(和版本,如果需要)列而不是自然键时,Hibernate真的更喜欢。根据我的经验,对复合/自然键的支持似乎很麻烦和错误。