等于 grails 中的域 class

Equals for domain class in grails

以下等于代码 returns 域的错误结果

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

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

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

如何避免此类问题?

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

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

equalshashCode 中使用 id 在领域 class 中通常不是一个好主意,因为您无法比较持久性和非持久性 class是的。例如

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

有了这个 class,这会失败:

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

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

更糟糕的是,假设您创建了一个同样损坏的 hashCode 方法,如果您将一个非持久实例添加到基于散列的集合(例如 HashSet)然后保存它,它的id 将从 null 变为某个 long 值,其哈希码值也将如此。这将导致该实例成为集合中的 "lost"。

GormInstanceApi中的特殊方法在哪里

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

使用这个方法解决了问题