JPA OneToMany Cacade.ALL 为父项创建两个条目
我们在项目中使用 JPA-Hibernate
我们有一个实体,比如说 A,它有一个实体 B 列表。
在 A 内,B 列表上有一个 OneToMany 在 B 中,A 上有一个 ManyToOne 在
A 中,对于 B 列表,我放置了 CascadeType.ALL,并且有一种将 B 添加到 A 中的方法
我仅通过 A 保存所有 B 实体。
假设我创建了 A1 并将两个B.. B1和B2添加到A中并保存A。
A a1 = createA(...);
B b1 = createB(....);
B b2 = createB(....);
a1.addB(b1); //Internally does b1.setA(this) as well
a1.addB(b2); //Internally does b1.setA(this) as well
a1 = ADao.save(a1);
但是当创建DB中的条目时,为A创建了两个条目。
一个 id=0,一个 id=1.. b1 和 b2 的条目引用了 id=0 的 A 的条目。
但是,如果我们首先保存 a1,然后将 b1,b2 添加到 a1,然后再次保存 a1,则它工作正常,并且仅使用 id = 1 创建 A 的一个条目
请让我知道我做错了什么或其工作方式它应该吗?
谢谢
实体 A = Bill, B = BillLineitem
类的代码:
@Entity
@Table(name = "bills")
public class Bill implements Serializable {
private static final long serialVersionUID = -6523700369290034565L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", nullable = false)
private long id;
...
@Basic
@Column(name = "bill_number", nullable = false)
private String billNumber;
@Basic
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "date", nullable = false)
private Date billDate;
@Basic
@Column(name = "bill_amount", nullable = false)
private float billAmount;
..
@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
//@JoinColumn(referencedColumnName = "id")
@JoinColumn(name = "bill_id", nullable = true)
private List<BillLineitem> billLineitems;
/**
* @return the id
*/
public long getId() {
return id;
}
...
/**
* @return the billLineitems
*/
public List<BillLineitem> getBillLineitems() {
return billLineitems;
}
/**
* @param billLineitems the billLineitems to set
*/
public void setBillLineitems(final List<BillLineitem> billLineitems) {
this.billLineitems = billLineitems;
for (BillLineitem billLineitem : this.billLineitems) {
billLineitem.setBill(this);
billLineitem.setBillDate(this.getBillDate());
billLineitem.setOrganization(this.getOrganization());
billLineitem.setStore(this.getStore());
billLineitem.setUser(this.getUser());
}
}
public void addBillLineitem(BillLineitem billLineitem)
{
billLineitem.setBill(this);
billLineitem.setBillDate(this.getBillDate());
billLineitem.setOrganization(this.getOrganization());
billLineitem.setStore(this.getStore());
billLineitem.setUser(this.getUser());
if(this.billLineitems == null)
this.billLineitems = new ArrayList<BillLineitem>();
this.billLineitems.add(billLineitem);
}
....
}
@Entity
@Table(name = "bill_lineitems")
public class BillLineitem implements Serializable {
private static final long serialVersionUID = -4094587645624924794L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", nullable = false)
private long id;
@ManyToOne
@JoinColumn(name = "bill_id", nullable = false)
private Bill bill;
@Basic
@Column(name = "item_code", nullable = false)
private String itemCode;
@Basic
@Column(name = "amount", nullable = false)
private float amount;
/**
* @return the id
*/
public long getId() {
return id;
}
/**
* @return the bill
*/
public Bill getBill() {
return bill;
}
/**
* @param bill the bill to set
*/
public void setBill(final Bill bill) {
this.bill = bill;
}
..
/**
* @return the serial
*/
public int getSerial() {
return serial;
}
/**
* @param serial the serial to set
*/
public void setSerial(final int serial) {
this.serial = serial;
}
/**
* @return the itemCode
*/
public String getItemCode() {
return itemCode;
}
/**
* @param itemCode the itemCode to set
*/
public void setItemCode(final String itemCode) {
this.itemCode = itemCode;
}
...
}
We are using JPA-Hibernate in our project
We have a entity, say a A which has a list of entity Bs.
Within A, there is a OneToMany on list of Bs
Within B, there is a ManyToOne on A
In A, for the list of Bs, I have put CascadeType.ALL, and have a method for adding B into A
I save all my B entities only through A.
Lets say I create A1 and add two Bs.. B1 and B2 into A and save A.
A a1 = createA(...);
B b1 = createB(....);
B b2 = createB(....);
a1.addB(b1); //Internally does b1.setA(this) as well
a1.addB(b2); //Internally does b1.setA(this) as well
a1 = ADao.save(a1);
But when the entries in the DB are created, two entries for A is created.
One with id=0 and one with id=1.. And the entries for b1 and b2 refer to the entry of A with id=0.
However, If we first save a1 and then add b1,b2 to a1 and then save a1 again, it works fine and only one entry for A is created with id = 1
Please let me know what am I doing wrong or its working the way its supposed to ?
Thanks
Here Entity A = Bill, B = BillLineitem
The code for the classes:
@Entity
@Table(name = "bills")
public class Bill implements Serializable {
private static final long serialVersionUID = -6523700369290034565L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", nullable = false)
private long id;
...
@Basic
@Column(name = "bill_number", nullable = false)
private String billNumber;
@Basic
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "date", nullable = false)
private Date billDate;
@Basic
@Column(name = "bill_amount", nullable = false)
private float billAmount;
..
@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
//@JoinColumn(referencedColumnName = "id")
@JoinColumn(name = "bill_id", nullable = true)
private List<BillLineitem> billLineitems;
/**
* @return the id
*/
public long getId() {
return id;
}
...
/**
* @return the billLineitems
*/
public List<BillLineitem> getBillLineitems() {
return billLineitems;
}
/**
* @param billLineitems the billLineitems to set
*/
public void setBillLineitems(final List<BillLineitem> billLineitems) {
this.billLineitems = billLineitems;
for (BillLineitem billLineitem : this.billLineitems) {
billLineitem.setBill(this);
billLineitem.setBillDate(this.getBillDate());
billLineitem.setOrganization(this.getOrganization());
billLineitem.setStore(this.getStore());
billLineitem.setUser(this.getUser());
}
}
public void addBillLineitem(BillLineitem billLineitem)
{
billLineitem.setBill(this);
billLineitem.setBillDate(this.getBillDate());
billLineitem.setOrganization(this.getOrganization());
billLineitem.setStore(this.getStore());
billLineitem.setUser(this.getUser());
if(this.billLineitems == null)
this.billLineitems = new ArrayList<BillLineitem>();
this.billLineitems.add(billLineitem);
}
....
}
@Entity
@Table(name = "bill_lineitems")
public class BillLineitem implements Serializable {
private static final long serialVersionUID = -4094587645624924794L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", nullable = false)
private long id;
@ManyToOne
@JoinColumn(name = "bill_id", nullable = false)
private Bill bill;
@Basic
@Column(name = "item_code", nullable = false)
private String itemCode;
@Basic
@Column(name = "amount", nullable = false)
private float amount;
/**
* @return the id
*/
public long getId() {
return id;
}
/**
* @return the bill
*/
public Bill getBill() {
return bill;
}
/**
* @param bill the bill to set
*/
public void setBill(final Bill bill) {
this.bill = bill;
}
..
/**
* @return the serial
*/
public int getSerial() {
return serial;
}
/**
* @param serial the serial to set
*/
public void setSerial(final int serial) {
this.serial = serial;
}
/**
* @return the itemCode
*/
public String getItemCode() {
return itemCode;
}
/**
* @param itemCode the itemCode to set
*/
public void setItemCode(final String itemCode) {
this.itemCode = itemCode;
}
...
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
这是因为您将相同的双向关联映射了两次:一次在
Bill
中(在项目列表上使用@JoinColumn(name = "bill_id", nullable = true)
),一次进入BillLineitem
(在bill
字段上使用@JoinColumn(name = "bill_id", nullable = false)
)。OneToMany 端应仅标记为 ManyToOne 端的逆关联,并且项目列表应仅使用
@OneToMany(fetch = FetchType.LAZY,cascade = CascadeType.ALL,mappedBy = "bill") 进行注释
。删除@JoinColumn
注释。This is because you mapped the same bidirectional association twice: once in
Bill
(with@JoinColumn(name = "bill_id", nullable = true)
on the list of items), and once inBillLineitem
(with@JoinColumn(name = "bill_id", nullable = false)
on thebill
field).The OneToMany side should just be marked as the inverse association of the ManyToOne side, and the list of items should just be annotated with
@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "bill")
. Remove the@JoinColumn
annotation.