开发者

JPA OneToMany Cacade.ALL creating two entries for the parent

开发者 https://www.devze.com 2023-03-31 11:20 出处:网络
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

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.

0

精彩评论

暂无评论...
验证码 换一张
取 消