Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/391.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/0/jpa/2.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 Eclipselink插入ID为0的实体_Java_Jpa_Eclipselink - Fatal编程技术网

Java Eclipselink插入ID为0的实体

Java Eclipselink插入ID为0的实体,java,jpa,eclipselink,Java,Jpa,Eclipselink,我刚刚发现EclipseLink(2.3.0和2.4.1)有一个相当奇怪的问题,我只是想问问是否有人能确认这是一个bug,而不仅仅是我遗漏了一些明显的东西 基本上,我涉及到两个实体,让我们简单地称它们为A和B。A有一个渴望的(如果这有关系的话),对B的非级联多对一单向引用,在数据库中用连接列建模。DB表A包含列ID(PK)、B_ID(FK到B.ID)等,表B包含列ID等 现在,我有了一个As列表,应该用对新B实例的引用来更新它。在伪代码中,类似于: for(A a : list) { /

我刚刚发现EclipseLink(2.3.0和2.4.1)有一个相当奇怪的问题,我只是想问问是否有人能确认这是一个bug,而不仅仅是我遗漏了一些明显的东西

基本上,我涉及到两个实体,让我们简单地称它们为A和B。A有一个渴望的(如果这有关系的话),对B的非级联多对一单向引用,在数据库中用连接列建模。DB表A包含列ID(PK)、B_ID(FK到B.ID)等,表B包含列ID等

现在,我有了一个As列表,应该用对新B实例的引用来更新它。在伪代码中,类似于:

for(A a : list) {
    // using some criteria, check if perhaps a matching B
    // entity is already found in the database
    B b = perhapsGetExistingBFromDatabase();

    if(b == null) {
        // no existing B was found, create a new
        b = new B();
        // set values in B
        b.setFoo(4711),
        b.setBar(42);

        // save B
        em.merge(b);
    }

    // set reference from A to B ...
    a.setB(b);
    // ... and update A
    em.merge(a);
}
因为引用是非级联的,所以有必要合并b和a。一切如期进行

然后,有人(我)将关系的级联类型从none更改为merge/persist,因为这在代码的其他地方是必需的。我希望旧代码可以工作,合并b并不是真的需要,IMHO不应该受到伤害吗?一个简短的测试确认它仍然有效,插入了新的B实体,并相应地更新了A

但是,只有当列表中只有一个实体时,它才起作用。第二次运行循环会导致EclipseLink自动刷新会话,因为
可能存在bFromDatabase
执行了一个“SELECT..FROM B”,缓存了一个合并的B实体,它希望数据库表是最新的。使用代码中最精细的日志记录级别和断点,我可以验证EclipseLink是否确定需要为新的B实体生成id,它调用序列生成器,并在实体的正确字段中设置id。尽管如此,EclipseLink调用的SQL语句与以下类似:

INSERT INTO B (ID, ...) VALUES(0, ...);
UPDATE A SET B_ID = 0 WHERE ID = ...;
生成的id丢失在某处,EclipseLink尝试创建id为0的新实体。数据确实无效,稍后,EclipseLink还会抛出PersistenceException:在工作单元克隆中遇到Null或零主键

虫子还是我的错


编辑:James要求提供B.ID:

@Id
@GeneratedValue(generator = "sq_idgen", strategy = GenerationType.SEQUENCE)
@SequenceGenerator(name = "sq_idgen", sequenceName = "...", allocationSize = 100)
@Column(name = "id")
protected long id;

注意,删除不必要的
em.merge(b)解决了我的问题。我不明白为什么调用merge会导致EclipseLink完全失败,试图插入一个没有填充id的B实例。

奇怪的是,B的id是如何映射的

似乎合并后的数据库可能会以某种方式获得两个单独的B实例(因为没有标识它们是相同的,因为它们没有Id)。并不是说merge()通常不是必需的,它只对分离的对象是必需的,例如在使用序列化时(尝试使用persist)


为了避免刷新,您可以在EntityManager或持久性单元中将flushMode设置为COMMIT而不是AUTO。

我已将id映射添加到原始问题中。在本例中,合并b实际上是必需的,因为它是一个新对象。若我将它持久化,它的id就不会立即更新,也就无法将它和现有的a实例连接起来。在这种情况下,自动刷新模式也是正确的,因为我可能会创建B的新实例,这可以在以后的循环迭代中通过
perhapsGetExistingBFromDatabase
找到。