使用自然键作为equals和hashCode的一部分

时间:2010-09-24 18:25:46

标签: java hibernate jpa

我知道这个话题已经讨论了很多次,但仍然需要对我们面临的问题作一些澄清。 Hibernate best practices谈论使用自然键进行equals / hashCode方法。我们有一个复合键,它由一个特定对象所属的2个参数(比如String name,Organization org)组成。不幸的是我不能使用org,因为它是懒惰加载并导致其他问题,我也不想创建代理键(可能是从数据库自动生成的,也可能是在创建对象之前通过API调用创建的UUID)。我真正拥有什么样的选项,因为在上面的Object(name,org)字段中是唯一的,我不能只根据名称字段本身编写我的逻辑。代理键是唯一的选项,这是否意味着我必须将此值存储为表中每行的一部分?

3 个答案:

答案 0 :(得分:4)

如果你想要像

那样的话
public class MyEntity {

    private String name;

    private Organization organization;

    // getter's and setter's

    public boolean equals(Object o) {
        if(!(o instanceof MyEntity))
            return false;

        MyEntity other = (MyEntity) o;
        return new EqualsBuilder().append(getName(), other.getName())
                                  .append(getOrganization(), other.getOrganization())
                                  .isEquals();
    }

}

但是如果你想避免它,因为你现在想要加载一个延迟加载的实体,你可以依靠Hibernate.isInitialized方法并提供你的自定义例程

public boolean equals(Object o) {
    if(!(o instanceof MyEntity))
        return false;

    MyEntity other = (MyEntity) o;
    boolean equals = new EqualsBuilder().append(getName(), other.getName())
                                        .isEquals();

    if(Hibernate.isInitialized(getOrganization())) {
       // loaded Organization
    } else {
       // supply custom routine
    }

    return equals;
}

我有一个未更新的网页,其中Hibernate提供以下矩阵

                                        no eq/hC at all  eq/hC with the id property  eq/hC with buisness key
use in a composite-id                   No               Yes                         Yes
multiple new instances in set           Yes              No                          Yes
equal to same object from other session No               Yes                         Yes
collections intact after saving         Yes              No                          Yes        

其中各种问题如下:

在复合ID中使用

  

要将对象用作复合id,它必须以某种方式实现equals / hashCode,在这种情况下== identity将不够。

集合中的多个新实例

以下是否有效:

HashSet someSet = new HashSet();
someSet.add(new PersistentClass());
someSet.add(new PersistentClass());
assert(someSet.size() == 2);

等于来自其他会话的同一对象

以下是否有效:

PersistentClass p1 = sessionOne.load(PersistentClass.class, new Integer(1));
PersistentClass p2 = sessionTwo.load(PersistentClass.class, new Integer(1));
assert(p1.equals(p2));
保存后

收藏完整

以下是否有效:

HashSet set = new HashSet();
User u = new User();
set.add(u);
session.save(u);
assert(set.contains(u));

它还强调了这个Thread,其中讨论了equals / hashCode实现

答案 1 :(得分:2)

  

Hibernate最佳实践谈论使用equals / hashCode方法的自然键。

是的,所以我不会详细说明。

  

我们有一个复合键,它由一个特定对象所属的2个参数(比如String name,Organization org)组成。不幸的是,我不能使用org,因为它是懒惰加载并导致其他问题。

你能详细说一下,也许用一些代码说明一下吗?我想了解你是如何准确地完成这项工作的,以及问题是什么。

  

我真正拥有什么样的选项,因为在上面的Object(name,org)字段中是唯一的,我不能只根据名称字段本身编写逻辑。

正如我所说,提供更多细节可能有所帮助。但为了以防万一,请注意,只要您使用property access type,在代理上调用org.getId()就不应该触发实体的加载,因此您应该能够在等于实现中使用它

答案 2 :(得分:0)

什么是被称为具有名称和组织的对象?我猜它叫做Foo。我认为你不能说foo.getOrganization()因为数据库连接已关闭?您是否可以更改您的FooDAO,以便在从数据库中读取foo后立即加载组织?

然后,当您需要使用equals()和hashCode()时,它将可用。