Java entitymanager.merge()的行为与我预期的不一样(创建新记录而不是更新)

Java entitymanager.merge()的行为与我预期的不一样(创建新记录而不是更新),java,postgresql,jpa,merge,eclipselink,Java,Postgresql,Jpa,Merge,Eclipselink,我在搜索中找不到任何相关信息。根据从导出的CSV读取的数据是否存在以前的记录,我正在进行批量插入和/或更新 下面的内容将在数据库中保留两条记录,而我希望它插入并更新同一条记录 如果数据库中已经有一条记录,它将按预期工作,只需更新现有行 之前,我检查了一下是否为null,然后做了if/else来插入/更新,一切正常。在二传中有很多冗余,所以我把它改成了这个。我的希望是,它将始终运行更新,但如果没有找到记录,它将创建一个最小可行的病理记录,随后进行更新。更新工作正常-问题是当没有以前的记录存在时,它

我在搜索中找不到任何相关信息。根据从导出的CSV读取的数据是否存在以前的记录,我正在进行批量插入和/或更新

下面的内容将在数据库中保留两条记录,而我希望它插入并更新同一条记录

如果数据库中已经有一条记录,它将按预期工作,只需更新现有行

之前,我检查了一下是否为null,然后做了if/else来插入/更新,一切正常。在二传中有很多冗余,所以我把它改成了这个。我的希望是,它将始终运行更新,但如果没有找到记录,它将创建一个最小可行的病理记录,随后进行更新。更新工作正常-问题是当没有以前的记录存在时,它会创建一个额外的记录

这是因为合并和提交事务的位置和方式吗?我不明白为什么第二次合并会在我向它传递一个必须已经存在的要更新的对象时创建一个新的插入

我可以让一切按照我的意愿运行,但我想更好地理解为什么这不是我所期望的。我是否缺少关于合并和事务的核心概念

这是我的密码

        Pathology pathology = getPathology(entityManager, slideId, mdCallString, CALLTYPE);

        if(null==pathology) {
            entityManager.getTransaction().begin();
                pathology = new Pathology();
                pathology.setSlideId(slideId);
                pathology.setCallType(CALLTYPE);
                pathology.setCallBy(mdCallString);
            entityManager.merge(pathology);
            entityManager.getTransaction().commit();
        }

        entityManager.getTransaction().begin();
            pathology.setSample(sample);
            pathology.setSlides(slides);
            pathology.setLocation(location);
            pathology.setCallDx(sampleLevelDx);
            pathology.setPatientDx(patientLevelDx);
            pathology.setRadiologyReports(radiologyReports);
            pathology.setModality(MODALITY);
            pathology.setUpdatedOn(new Date());
            String dtm = lineContainer.get(lineContainer.size() - 1);
            DateFormat sdf = new SimpleDateFormat("MM/dd/yyyy hh:mm a", Locale.US);
            Date callDate = sdf.parse(dtm);
            pathology.setCallDate(callDate);
            if(mdCallString==colbyCallString) {
                pathology.setRepresentativeSlideDigitized(currentSlide.get(3));
            }
        entityManager.merge(pathology);
        entityManager.getTransaction().commit();
编辑:所以,如果我跑步,一切都会像我希望的那样工作

        Pathology pathology = getPathology(entityManager, slideId, mdCallString, CALLTYPE);

        if(null==pathology) {
            entityManager.getTransaction().begin();
                pathology = new Pathology();
                pathology.setSlideId(slideId);
                pathology.setCallType(CALLTYPE);
                pathology.setCallBy(mdCallString);
            entityManager.merge(pathology);
            entityManager.getTransaction().commit();
        }

        pathology = getPathology(entityManager, slideId, mdCallString, CALLTYPE);

        entityManager.getTransaction().begin();
            pathology.setSample(sample);
            pathology.setSlides(slides);
            pathology.setLocation(location);
            pathology.setCallDx(sampleLevelDx);
            pathology.setPatientDx(patientLevelDx);
            pathology.setRadiologyReports(radiologyReports);
            pathology.setModality(MODALITY);
            pathology.setUpdatedOn(new Date());
            String dtm = lineContainer.get(lineContainer.size() - 1);
            DateFormat sdf = new SimpleDateFormat("MM/dd/yyyy hh:mm a", Locale.US);
            Date callDate = sdf.parse(dtm);
            pathology.setCallDate(callDate);
            if(mdCallString==colbyCallString) {
                pathology.setRepresentativeSlideDigitized(currentSlide.get(3));
            }
        entityManager.merge(pathology);
        entityManager.getTransaction().commit();
第二次,在检查null的块之后。但我希望避免重复。关于最初的问题,在两个导致不同结果的病例中,病理变量中传递的内容有什么区别?在这两种情况下,它们都引用数据库中相同的现有记录-那么为什么一个导致插入,而另一个执行更新呢


谢谢

也许解决了?仔细考虑之后,似乎在第一次合并和提交之后,当以前不存在任何记录时,病理变量无法知道其对象是持久化的。pgsql正在生成其串行pk列。因此,当它第二次尝试合并时,除非在初始插入之后查询实体以获取唯一标识符,否则实体管理器无法判断记录是否需要更新。如果有人能更好地解释这一点,我欢迎并感谢你的见解。您是如何告诉JPA您的ID是如何生成的?展示实体会有所帮助。另外,由于您正在调用getPathologyentityManager、slideId、mdCallString、CALLTYPE;两次,如果它是一个没有设置ID的新实体,那么第二次也不会设置ID。您可以尝试在第一次检查时调用persist而不是merge,因为这将为传入的病理实例分配ID。如果GetPhysathy返回相同的实例,则merge将按预期工作。