2013-03-05 51 views
-1

我刚刚发现EclipseLink(2.3.0和2.4.1)的一个相当奇怪的问题,只是想问问是否有人可以确认这是一个错误,而不仅仅是我缺少一些东西显然...Eclipselink插入实体与0 ID

基本上,我有两个实体参与,让我们简单地称他们为A和B.一个渴望(如果有的话),非级联多对一的单向引用B建模在带连接列的数据库。数据库表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是不是真的需要,不应该恕我直言,但伤害?一个简短的测试证实它仍然有效,插入新的B实体并相应地更新A实体。

但是,它只适用于列表中只有一个A实体。第二次运行循环会导致EclipseLink自动刷新会话,因为perhapsGetExistingBFromDatabase执行“SELECT .. FROM B”,因此存在合并的B实体缓存,并且希望数据库表保持最新状态。在代码中使用FINEST日志记录级别和断点,我可以验证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:在工作单元克隆中遇到空或零主键。

错误或我的错误?


编辑:詹姆斯问B.ID的映射:

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

注意,即去除unneccesary em.merge(b);解决我的问题。这对我来说并不明显,为什么调用合并会导致EclipseLink完全失败,试图插入没有填充ID的B实例。

回答

0

这很奇怪,B的Id如何映射?

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

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

+0

我已经添加了id映射到我原来的问题。在这种情况下合并b实际上是必需的,因为它是一个新对象。如果我坚持了它,它的id不会立即更新,并且我不能将它与现有的实例连接起来。在这种情况下,自动刷新模式也是正确的,因为我可以创建新的B实例,在稍后的循环迭代中可以通过'maybeGetExistingBFromDatabase'找到它。 – jarnbjo 2013-03-05 16:03:04