JPA OneToMany Cacade.ALL создает две записи для родителя - PullRequest
0 голосов
/ 26 августа 2011

Мы используем JPA-Hibernate в нашем проекте

У нас есть объект, скажем, A, у которого есть список объектов B.

В пределах A есть OneToMany в спискеB В B есть ManyToOne на A

В A, для списка B, я поместил CascadeType.ALL, и у меня есть метод для добавления B в A

. Я сохраняю всемои B-сущности только через A.

Допустим, я создаю 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);

Но когда записи в БДсоздано, две записи для А. созданы.

Одна с идентификатором = 0 и одна с идентификатором = 1 .. А записи для b1 и b2 относятся к записи А с идентификатором = 0.

Однако, если мы сначала сохраним a1, а затем добавим b1, b2 к a1, а затем снова сохраним a1, он будет работать нормально, и будет создана только одна запись для A с id = 1

Пожалуйста, дайте мне знать, чтоЯ делаю неправильно или он работает так, как предполагалось?

Спасибо

Здесь Entity A = Bill, B = BillLineitem

Код для классаes:

@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;
}

...

}

1 Ответ

0 голосов
/ 28 августа 2011

Это потому, что вы дважды отобразили одну и ту же двунаправленную связь: один раз в Bill@JoinColumn(name = "bill_id", nullable = true) в списке элементов) и один раз в BillLineitem@JoinColumn(name = "bill_id", nullable = false) в поле bill).

Сторона OneToMany должна быть просто помечена как обратная ассоциация стороны ManyToOne, а список элементов должен быть помечен @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "bill"). Удалить аннотацию @JoinColumn.

...