Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/373.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/hibernate/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 对于持久对象,等于_Java_Hibernate_Jpa_Persistence_Identity - Fatal编程技术网

Java 对于持久对象,等于

Java 对于持久对象,等于,java,hibernate,jpa,persistence,identity,Java,Hibernate,Jpa,Persistence,Identity,对于具有数据库管理id的持久性对象,实现equals()(和hashCode(),我将只讨论equals())存在一个众所周知的问题。 新对象未存储在数据库中,因此没有数据库标识,因此其“id”字段为空(如果是基元类型,则为0) 如果等值为ID,它会考虑所有新的对象是相等的,一旦它得到ID,哈希代码就会改变,所以如果它已经在哈希敏感集合中,它就不会被找到。 一种解决方案是使用业务密钥,但有时除了代理id之外的所有内容都是可变的。 另一个解决方案是在创建对象时生成(一个或多个,或将其用作数据库id

对于具有数据库管理id的持久性对象,实现equals()(和hashCode(),我将只讨论equals())存在一个众所周知的问题。 新对象未存储在数据库中,因此没有数据库标识,因此其“id”字段为空(如果是基元类型,则为0)

如果等值为ID,它会考虑所有新的对象是相等的,一旦它得到ID,哈希代码就会改变,所以如果它已经在哈希敏感集合中,它就不会被找到。 一种解决方案是使用业务密钥,但有时除了代理id之外的所有内容都是可变的。 另一个解决方案是在创建对象时生成(一个或多个,或将其用作数据库id)代理项id

我并没有提到的方法是,在equals中使用id,并在id为null时使equals(和hashCode())失败(抛出IllegalStateException)。(并记录此行为) 这样,它仍然不能在散列集合中,但不能意外地放在那里。当没有id时,可以使用一些包装器将其放入集合中。 这主意好/坏吗?它有可怕的问题吗

正如kan所指出的,如果子对象应该放在Set属性中并与其父对象一起持久化,那么在持久化之前无法将对象放在Set中是一个大问题(TreeSet没有帮助,因为它使用equals(),即使它不使用hashCode())。
我主要使用列表来表示子实体,所以它不需要显示,但这肯定是个问题。

我总是使用自动生成的id,从来没有遇到过问题。当实例化对象时,您可以使用您的服务层/工厂强制执行该对象

我认为任何其他字段(组成一个biz键)发生变化的可能性要比在hashmap中使用一个非持久化对象,然后同时持久化导致查找失败的可能性大得多

imho,这个问题有点复杂。自动生成的id通常是我想要做的唯一平等性测试,在很多情况下,其他任何测试都没有意义。我采用的方法是,如果正在使用/比较一个非持久化对象,那么问题在于业务逻辑,而不是底层的equals/hashcode方法


为了明确回答illegalstateexception的想法,当对象不相等和/或未被持久化时抛出异常似乎非常引人注目。

我使用下一段代码。它涵盖了大多数情况,并且可以用于我认为在使用ORM时可能发生的所有情况

public class VersionedEntity
{
        private static final long serialVersionUID=1L;
        private Long id;
        private long version;
        @Transient
        private int hashCode;
...
        public void setId(final Long id)
        {
            if(this.id != null && !this.id.equals(id))
                throw new IllegalArgumentException(this+" has an ID already, cannot change it to "+id);
            this.id = id;
        }
        @Override
        public String toString() {
            return getClass().getName()+'#'+getId();
        }

        public boolean equals(final Object o)
        {
            if (this==o) return true;
            if (!(o instanceof VersionedEntity))
                return false;
            final VersionedEntity entity=(VersionedEntity) o;
            final Long id1 = entity.getId();
            final Long id2 = getId();
            if(id1==null && id2==null)
                return super.equals(o);
            return id1 != null
                   && id2 != null
                   && id2.equals(id1);

        }

        public int hashCode()
        {
            if(hashCode == 0)
            {
                hashCode = id != null ? id.hashCode() : super.hashCode();
                if(hashCode == 0)
                    hashCode = 42;
            }
            return hashCode;
        }
}

在分配id之前,您必须能够使用集合。如果您想创建一个具有
属性的对象,该属性包含一组其他对象,您必须将它们作为元素添加到

创建对象时如何强制设置id?这只是表明,当两个对象的id为null时,将调用超类的方法。哈希代码也是如此。我不明白你为什么认为这样更好。我可以创建一个新对象并在集合中使用它。当放入集合时,id可以为null,之后我可以设置setid()。这根本解决不了问题。两个id为null的新对象将只调用super类的方法。只要仔细阅读代码,在这种情况下它将正常工作。我错过什么了吗?什么案子!1.我创建了一个id为空的新对象,我把它放在集合中。然后我的代码在别处更改id。从hashmap查找将失败。2.id为null的新对象的计算结果是否相等?你们给hashcode赋值42,这肯定是个笑话?让我们来看看我的想法是,我会抛出,不是因为它们不相等,而是因为用户现在不应该问它们是否相等。这样就解决了商业中的问题。日志它可以被指出,但它不是固定不变的。用户将收到一条错误消息。唯一100%安全的方法是在对象创建()时为对象生成id。但正如我所说的,我一直都在使用db id,请确保您记录了代码,这样您就不会有问题了。我希望开发人员收到错误消息,并让他更改代码。我将在当前项目中使用我的投掷等式,用于在任何有意义的活动之前持久化的类。但它肯定不是通用的解决方案。创建时自动生成的id可能是通用解决方案。不幸的是,它不是通用解决方案。阅读我答案下面的讨论。