我有一个类User,它充当数据库中Users表的Persistence模型:
public class User {
@Id
@Basic(optional = false)
@Column(name = "USER_ID")
private Long userId;
@JoinColumn(name = "LAST_CHANGED_USER_ID", referencedColumnName = "USER_ID")
@ManyToOne(fetch = FetchType.LAZY)
private User lastChangedUser;
...
@Override
public int hashCode() {
int hash = 0;
hash += (userId != null ? userId.hashCode() : 0);
return hash;
}
@Override
public boolean equals(Object object) {
if (!(object instanceof User)) {
return false;
}
User other = (User) object;
if ((this.userId == null && other.userId != null) ||
(this.userId != null && !this.userId.equals(other.userId))) {
return false;
}
return true;
}
@Override
public String toString() {
return "User[userId=" + userId + "]";
}
}
只要对User实例进行了更改,就会更新字段lastChangedUser。请考虑以下方法:
private void setUsername(string username, User lastChangedUser){
this.username = username;
this.lastChangedUser = lastChangedUser;
}
public void updateUserName(Long userId, Long lastChangedUserId, String username){
EntityManager em = PersistenceManager.getPersistenceManager()
.getEntityManager();
EntityTransaction transaction = em.getTransaction();
User user = em.find(User.class, userId);
User lastChangedUser = em.find(User.class, lastChangedUserId);
transaction.begin();
user.setUsername(username, lastChangedUser);
transaction.commit();
}
和单元测试:
public void testUpdateUsername(){
UserFacade instance = new UserFacade();
User john = instance.getUserByUserId(new Long(1));
User jane = instance.getUserByUserId(new Long(2));
// make the update and persist
instance.updateUsername("JANE M. DOE", jane.userId, john.userId);
// assert that john made the change to jane
jane = instance.getUserByUserId(new Long(2));
assertTrue(jane.username.equals("JANE M. DOE"));
User actual = jane.lastChangedUser;
User expected = john;
// this assertion passes...
assertTrue(actual.equals(expected));
// yet this assertion fails!
assertTrue(expected.equals(actual));
// this fails as well.
assertEquals(expected, actual);
}
使用Netbeans 7.1.1,测试结果屏幕返回错误消息:
FAILED: expected: User[id=1], but was: User[id=1].
检查时,对象actual
的类型不是User
,而是代理对象的类型。我假设这是由于LAZY获取注释。因此,对象的userid的值为null
,expected.equals(actual)
返回false
。但是,actual.equals(expected)
会返回true
。为了增加我的困惑,失败消息显示actual.userId
不是null
,而是等于预期的ID!
Hibernate或JUnit的一些怪癖导致实际的User对象在失败后出现?
答案 0 :(得分:1)
有些朋友和我通过a question about obtaining ids without fetching the entire object找到了解决方案。由于对象是代理,因此直接在userid
中重新生成字段equals
会产生空值。但是,对用户标识使用 getter方法会导致从数据库中获取实际值。因此,equals
方法应如下所示:
@Override
public boolean equals(Object object){
if (!(object instanceof User)) {
return false;
}
User other = (User) object;
if ((this.getUserId() == null && other.getUserId() != null) ||
(this.getUserId() != null &&
!this.getUserId().equals(other.getUserId()))) {
return false;
}
return true;
}
现在断言将成立。