Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/308.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_Identity - Fatal编程技术网

试图保存代表同一实体的不同java对象。冬眠

试图保存代表同一实体的不同java对象。冬眠,java,hibernate,identity,Java,Hibernate,Identity,(这是对实际问题的简化) 让我们从以下小班开始: @Entity class Test { Test(int id, String name) { this.id = id; this.name = name; } @Id private int id; @Column private String name; @Override

(这是对实际问题的简化)

让我们从以下小班开始:

@Entity
class Test {
        Test(int id, String name) {
            this.id = id;
            this.name = name;
        }

        @Id
        private int id;

        @Column
        private String name;

        @Override
        public int hashCode() {
            return id;
        }

        @Override
        public boolean equals(Object obj) {
            if (obj instanceof Test) {
                return id == ((Test) obj).id;
            }
            return false;
        }
    }
如果我们执行以下操作,则不会发生异常:

EntityManagerFactory factory = Persistence.createEntityManagerFactory("local_h2_persistence");
EntityManager theManager = factory.createEntityManager();
EntityTransaction t = theManager.getTransaction();

Test obj1  = new Test(1, "uno");

tA.begin();
AtheManager.persist(obj1);
AtheManager.persist(obj1); // <-- No exception
tA.commit();
EntityManagerFactory工厂=Persistence.createEntityManagerFactory(“本地持久化”);
EntityManager theManager=factory.createEntityManager();
EntityTransaction t=manager.getTransaction();
测试obj1=新测试(1,“uno”);
tA.begin();
AtheManager.persist(obj1);

AtheManager.persist(obj1);// 在第一种情况下,保存同一对象两次,这是允许的。
但在第二种情况下,将两个不同的对象保存到数据库中,但它们都具有相同的主键。这是数据库约束冲突

在第一个示例中,您向一个对象传递一个引用以保存它,在第二个调用中,您传递了完全相同的引用;它们都指向内存中的同一对象


但是,在第二个示例中,您使用两个新调用分配了两个对象,这将在两个不同的内存地址创建对象;它们是两个不同的对象。第一个引用指向另一个内存地址,然后指向第二个对象的引用。如果您在第二个示例中尝试此操作,它将返回false:obj1==obj1

我只是在重写@jb nizet在评论中写的内容,这对我来说就像是答案:


Hibernate不使用==。它只是做你让它做的事。 persist的约定是:将此对象与会话关联。如果是 已经关联到会话,这是一个noop。如果不是,那就是 与稍后要插入数据库的会话关联。如果 您要做的是确保将此对象的状态复制到 一个持久性实体,然后将该持久性实体返回给我 您正在查找merge()

所以解决方法就是使用

AtheManager.merge(obj1);
而不是

AtheManager.persist(obj1);

它们有什么“不同”之处?它们代表相同的实体,因此不应违反数据库约束。一次只能有一个给定实体的实例在持久性上下文中。你想做的事毫无意义。假设这是允许的。如果将第一个对象的名称设置为“foo”,将第二个对象的名称设置为“bar”,Hibernate应该怎么做?它应该将foo或bar写入数据库吗?
obj1
obj1
是不同的Java对象-因此Hibernate认为它们应该在数据库表中创建两个不同的行-但这是不可能的,因为不可能有两个主键相等的行。@JBNizet obj1.equals(obj_1)=true,所以没有问题。如果名称不同,则obj1.equals(obj1_)=false。为什么Hibernate使用引用相等而不是值相等?Hibernate不使用==。它只是做你让它做的事。persist的约定是:将此对象与会话关联。如果它已经与会话关联,则它是一个noop。如果不是,它将与稍后插入数据库的会话相关联。如果您想做的是确保将此对象的状态复制到一个持久实体,并将该持久实体返回给我,那么您正在寻找merge()。我在问题中已经指出了这一点。问题是,为什么Hibernate使用引用相等而不是值相等,以及如何使它使用值相等?我猜它使用引用检查,因为这样可以保证值相等。记住,客户机代码可以自由覆盖equals;它的实现可以是始终返回true。执行内存位置检查更安全。这在equals实现中是一个问题,因此在这种情况下,未定义的行为是可以的。无论如何,难道没有办法实现我想要的吗?@JoséD。这样的“错误”会影响实体管理器的状态,这就是为什么它的设计者决定进行内存地址检查。尝试合并方法?我并不熟悉这个接口,但是从我从文档中读到的内容来看,您应该使用merge方法。
AtheManager.persist(obj1);