问题描述
我有两个实体,A和B。合并A时,我也希望合并B-所以我从不对B进行操作,而总是对A进行操作。可以通过A对象访问B对象。 ,反之亦然(如果可能),反之亦然。 A和B共享相同的主键字段,也就是说,B的主键字段是A的主键的外键。但是,我终于知道了 INSERT
查询的顺序正确,但是由于未在查询参数中绑定ID,因此会抛出 InsertNullViolation
,因为未设置主键。有谁知道如何使EclipseLink绑定诸如B之类的已连接对象的主键?
公共类A {
...
@Id
@Column(name = A_ID)
@SequenceGenerator(...)
@GeneratedValue(...)
公共长getA_ID();
@OneToOne(mappedBy = a,targetEntity = B.class)
public B getB();
...
}
公共类B {
...
@Id
public Long getA_ID();
MapsId
@ OneToOne(targetEntity = A.class)
@ JoinColumn(name = A_ID)
public A getA();
...
}
以上设置未设置主键
公共类A {
...
@Id
@Column(name = A_ID)
@SequenceGenerator(...)
@GeneratedValue(...)
public Long getA_ID();
@OneToOne(mappedBy = a,targetEntity = B.class)
public B getB();
...
}
公共类B {
...
@Id
@OneToOne(targetEntity = A.class)
@JoinColumn(name = A_ID)
public A getA();
...
}
此设置也有相同的问题。例外是:
内部异常:java.sql.SQLIntegrityConstraintViolationException:ORA-01400:无法将NULL插入( SOME_USER。 B。 A_ID)
错误代码:1400
调用:INSERT INTO B(SOME_FIELD1,SOME_FIELD2,...,A_ID)值(?,?,..., ?)
bind => [null,SOME_VALUE,...,null]
查询:InsertObjectQuery(packagename.B@ObjectId)
EclipseLink需要使用绑定线填充绑定行上的最后一个 null
,它使用先前插入对象A时从序列中检索到的实际ID。 $ b我要进行的合并基本上可以归结为:
public void merge(A objectA,B objectB){
objectA.setB(objectB);
entitymanager.merge(objectA);
}
问题似乎是您没有在B上设置A。
您必须保持双向关系,没有魔术为您做到这一点。
在创建A并分配B时,还必须将A分配给B,否则它为null,并将插入null。因此,您应该这样做而是:
public void merge(A objectA,B objectB){
A.setB(objectB); //因此,当您合并A时,它将知道B个对象
B.setA(objectA); //因此B知道要查看A对象的键
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。
请参见
I have two entities, A and B. When I merge A, I want B to be merged as well - so I never do operations on B, just always operations on A. The B object will be accessible via the A object, but not vice versa (if possible). A and B share the same primary key field, that is, the primary key field of B is a foreign key to the primary key of A. However, I've finally got it to the point where the INSERT
queries are in the correct order, but because it's not binding the ID in query parameters, it's throwing an InsertNullViolation
as the primary key is not set. Does anyone know how to get EclipseLink to bind the primary key for the joined objects like 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();
...
}
The above setup does not set the primary key on B so throws an InsertNullViolation trying to insert into 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();
...
}
This setup also has the same issue. The exception is:
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)
That last null
on the bind line needs to be filled in by EclipseLink with the actual ID that it previously retrieved from the sequence when it inserted object A.What I'm doing for merging boils down to essentially this:
public void merge(A objectA, B objectB) {
objectA.setB(objectB);
entitymanager.merge(objectA);
}
The issue seems to be that you are not setting the A on your B.
You must maintain bi-directional relationships, there is no magic that does this for you.
When you create your A and assign the B you also must assign the A to the B, otherwise it is null, and will insert null. Thus, you should be doing this instead:
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);
}
Further, in your first example, you also have a duplicate A_ID field in B, so you must also set this value when setting the A of B. Ensure you have persisted A first, otherwise its Id will be null, you could avoid this by removing the A_ID and putting the @Id on the OneToOne as you have done in your second example. You could also put insert/updateable=false in the A_ID and true in the OneToOne, then the foreign key value will come from the OneToOne.
You get the multiple writable mappings error because both the A_ID and the OneToOne map the same column, you need to mark one of them insert/updateable=false.
这篇关于Eclipselink与连接对象合并/持久化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!