我有两个实体,A和B.当我合并A时,我也希望B合并 - 所以我从不对B做操作,只是总是在A上操作.B对象可以通过A对象访问,但反之亦然(如果可能的话)。 A和B共享相同的主键字段,也就是说,B的主键字段是A的主键的外键。但是,我终于得到了INSERT
查询的点。按正确的顺序,但因为它没有绑定查询参数中的ID,所以它会抛出InsertNullViolation
,因为未设置主键。有谁知道如何让EclipseLink绑定像B这样的连接对象的主键?
public class A {
...
@Id
@Column(name = "A_ID")
@SequenceGenerator(...)
@GeneratedValue(...)
public Long getA_ID();
@OneToOne(mappedBy = "a", targetEntity = B.class)
public B getB();
...
}
public class B {
...
@Id
public Long getA_ID();
@MapsId
@OneToOne(targetEntity = A.class)
@JoinColumn(name="A_ID")
public A getA();
...
}
上面的设置没有在B上设置主键,因此抛出InsertNullViolation尝试插入B。
public class A {
...
@Id
@Column(name = "A_ID")
@SequenceGenerator(...)
@GeneratedValue(...)
public Long getA_ID();
@OneToOne(mappedBy = "a", targetEntity = B.class)
public B getB();
...
}
public class B {
...
@Id
@OneToOne(targetEntity = A.class)
@JoinColumn(name="A_ID")
public A getA();
...
}
此设置也存在同样的问题。例外是:
Internal Exception: java.sql.SQLIntegrityConstraintViolationException: ORA-01400: cannot insert NULL into ("SOME_USER"."B"."A_ID")
Error Code: 1400
Call: INSERT INTO B (SOME_FIELD1, SOME_FIELD2, ..., A_ID) VALUES (?, ?, ..., ?)
bind => [null, SOME_VALUE, ..., null]
Query: InsertObjectQuery(packagename.B@ObjectId)
绑定行上的最后一个null
需要由EclipseLink填充它在插入对象A时先前从序列中检索到的实际ID。
我正在做的合并归结为基本上这个:
public void merge(A objectA, B objectB) {
objectA.setB(objectB);
entitymanager.merge(objectA);
}
答案 0 :(得分:1)
以下是how to do it with Hibernate的文档。由于它是标准的JPA,您应该可以使用EclipseLink执行相同的操作。
您将B中的A_ID替换为A的映射OneToOne关联(并在另一侧使用mappedBy
),或者保留A_ID,还要向A添加OneToOne关联并使用{注释它{1}}(另外你也使用@MapsId
)。
答案 1 :(得分:1)
问题似乎是你没有在你的B上设置A.
你必须保持双向关系,没有任何魔法为你做到这一点。
当您创建A并分配B时,您还必须将A分配给B,否则它将为null,并将插入null。因此,您应该这样做:
public void merge(A objectA, B objectB) {
A.setB(objectB); //so when you merge A it knows about the B objects
B.setA(objectA); //so B knows to look at the A object for it's key
entitymanager.merge(objectA);
}
此外,在您的第一个示例中,您在B中也有一个重复的A_ID字段,因此您在设置A的B时也必须设置此值。确保您先保留A,否则其ID将为null,您可以通过删除A_ID并将@Id放在OneToOne上来避免这种情况,就像在第二个示例中所做的那样。您也可以在A_ID中插入insert / updateable = false,在OneToOne中输入true,然后外键值将来自OneToOne。
您得到多个可写映射错误,因为A_ID和OneToOne都映射到同一列,您需要标记其中一个insert / updateable = false。
答案 2 :(得分:0)
我收到此错误是因为我一直在做em.persist(父级),即使我一直在做parent.setChildren(child)。所以我不得不添加child.setParent(parent)。但它与你坚持的实体相关,因为你也可以做em.persist(孩子)。为简洁起见,尝试在两个实体中设置关系。
额外的评论,当我按照我之前所说的那样做时,我得到了一个" ORA-02291"错误,与我的外键不一致。这是因为我有一个TRIGGER设置我的表的PK,我也在我的实体中使用@SequenceGenerator。为了解决这个问题,我必须在我的TRIGGER中验证,如果:new.PK_TABLE为null,则只能将PK设置为MYSEQUENCE.nexval。
希望这可以帮助那些遇到同样麻烦的人,因为我从昨天开始就遇到了这个问题而且太浪费时间了。