【问题标题】:Using natural keys as part of equals and hashCode使用自然键作为 equals 和 hashCode 的一部分
【发布时间】:2011-04-16 22:25:24
【问题描述】:

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

【问题讨论】:

    标签: java hibernate jpa


    【解决方案1】:

    如果你想要类似的东西

    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,在这种情况下 == 身份是不够的。

    集合中有多个新实例

    以下是否有效:

    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 实现

    【讨论】:

    • 恕我直言,问题在于 hashCode 实现。我想知道 OP 如何使用他的延迟加载组织实现(一致的)hashCode。
    【解决方案2】:

    Hibernate 最佳实践讨论了对 equals / hashCode 方法使用自然键。

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

    我们确实有一个复合键,它由特定对象所属的 2 个参数(比如字符串名称、组织组织)组成。不幸的是,我无法使用 org,因为它被延迟加载并导致其他问题。

    您能否详细说明一下并用一些代码进行说明?我想了解你是如何让这个工作准确的以及问题是什么。

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

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

    【讨论】:

    • 用于指定属性访问策略,允许用户在不访问数据库的情况下获取关联实体的标识符
    【解决方案3】:

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

    然后当你需要用 equals() 和 hashCode() 做一些事情时,它会在以后可用。

    【讨论】:

      猜你喜欢
      • 2011-10-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-22
      • 2013-02-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多