【问题标题】:Equals for domain class in grails等于 grails 中的域类
【发布时间】:2015-04-07 20:05:45
【问题描述】:

以下等号代码为域返回错误结果

boolean equals(o) {
  if (o == null) return false
  if (this.is(o)) return true
  getClass() == o.class && id == o.id
}

对于两个加载的具有相同 id 的实体返回 false。 Id 相等(数据库中的一条记录)。但是类不一样。

实体——另一个域中的字段。看起来 GORM 使用了一些包装类。

如何避免此类问题?

【问题讨论】:

    标签: grails grails-orm


    【解决方案1】:

    如您所见,要求类相同过于严格。使用instanceof 通常更安全,例如

    class Foo {
        boolean equals(o) {
            if (!o) return false
            if (is(o)) return true
            o instanceof Foo && id == o.id
        }
    }
    

    equalshashCode 中使用id 在域类中通常是一个坏主意,因为您无法比较持久类和非持久类。例如

    class Foo {
        String name
        boolean equals(o) {
            if (!o) return false
            if (is(o)) return true
            o instanceof Foo && id == o.id
        }
    }
    

    使用这个类,这会失败:

    new Foo(name: 'foo').save()
    assert Foo.findByName('foo') == new Foo(name: 'foo')
    

    但所有重要的类数据(在本例中只是 name 属性)在两种情况下都是相同的。

    更糟糕的是,假设您创建了一个类似损坏的 hashCode 方法,如果您将非持久实例添加到基于哈希的集合(例如 HashSet)然后保存它,它的 id 将从null 到某个 long 值,其哈希码值也是如此。这将导致实例在集合中“丢失”。

    【讨论】:

    • 你无法比较持久类和非持久类——我知道。但受限于业务逻辑
    • 使用instanceof时,需要在编译时知道“B”的类。使用 isAssignableFrom() 时,它可以是动态的,并且在运行时会发生变化。 B.class.isAssignableFrom(a.getClass())
    【解决方案2】:

    GormInstanceApi 中的特殊方法在哪里

    /**
     * Proxy aware instanceOf implementation.
     */
    boolean instanceOf(D o, Class cls) {
        if (o instanceof EntityProxy) {
            o = (D)((EntityProxy)o).getTarget()
        }
        return o in cls
    }
    

    使用这种方法解决了问题

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-12-23
      • 1970-01-01
      • 2011-09-11
      • 2014-08-08
      • 2018-11-16
      • 1970-01-01
      • 2011-01-16
      • 1970-01-01
      相关资源
      最近更新 更多