JPA OneToMany Cacade.ALL creating two entries for the parent
We are using JPA-Hibernate in our project
We have a entity, say a A which has a list of entity Bs.
Wi开发者_如何转开发thin 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;
}
...
}
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 in BillLineitem
(with @JoinColumn(name = "bill_id", nullable = false)
on the bill
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.
精彩评论