JPA OneToMany Cacade.ALL 为父项创建两个条目

发布于 2024-12-01 15:37:48 字数 3775 浏览 5 评论 0原文

我们在项目中使用 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

天荒地未老 2024-12-08 15:37:49

这是因为您将相同的双向关联映射了两次:一次在 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 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文