1

データベース内のユーザーのテーブルの永続性モデルとして機能するクラスUserがあります。

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 + "]";
}
}

フィールドlastChangedUserは、Userインスタンスに変更が加えられるたびに更新されます。次の方法を検討してください。

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ではなく、Proxyオブジェクトのタイプです。これはLAZYフェッチアノテーションが原因だと思います。そのため、オブジェクトのユーザーIDはの値を持ち、nullexpected.equals(actual)返しますfalse。それでも、をactual.equals(expected)返しますtrue。私の混乱を増すために、失敗メッセージはそれがでactual.userIdはないnullが、期待されるIDと等しいことを示しています!

HibernateまたはJUnitのどのような癖が、失敗後に実際のUserオブジェクトを表示させていますか?

4

1 に答える 1

1

オブジェクト全体をフェッチせずにIDを取得することについての質問のおかげで、何人かの友人と私は解決策を見つけました。オブジェクトはプロキシであるため、でフィールドuseridを直接参照equalsするとnull値が生成されます。ただし、ユーザーIDに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;
}

そして今、アサーションは当てはまります。

于 2012-04-17T16:28:23.457 に答える