jpa 多层嵌套一对多_OpenJPA-嵌套的一对多关系合并问题

Trying to figure out if this is a problem with OpenJPA or something I may be doing wrong...

I'm facing a problem when trying to use OpenJPA to update an Entity that contains a One to Many relationship to another Entity, that has a One to Many relationship to another. Here's a quick example of what I'm talking about:

@Entity

@Table(name = "school")

public class School {

@Column(name = "id")

protected Long id;

@Column(name = "name")

protected String name;

@OneToMany(mappedBy = "school", orphanRemoval = true, cascade = CascadeType.ALL)

protected Collection classRooms;

}

@Entity

@Table(name = "classroom")

public class ClassRoom {

@Column(name = "id")

protected Long id;

@Column(name = "room_number")

protected String roomNumber;

@ManyToOne

@JoinColumn(name = "school_id")

protected School school;

@OneToMany(mappedBy = "classRoom", orphanRemoval = true, cascade = CascadeType.ALL, fetch = FetchType.EAGER)

protected Collection desks;

}

@Entity

@Table(name = "desk")

public class Desk {

@Column(name = "id")

protected Long id;

@ManyToOne

@JoinColumn(name = "classroom_id")

protected ClassRoom classRoom;

}

In the SchoolService class, I have the following update method:

@Transactional

public void update(School school) {

em.merge(school);

}

I'm trying to remove a Class Room from the School. I remove it from the classRooms collection and call update. I'm noticing if the Class Room has no desks, there are no issues. But if the Class Room has desks, it throws a constraint error as it seems to try to delete the Class Room first, then the Desks. (There is a foreign key constraint for the classroom_id column)

Am I going about this the wrong way? Is there some setting I'm missing to get it to delete the interior "Desk" instances first before deleting the Class Room instance that was removed?

Any help would be appreciated. If you need any more info, please just let me know.

Thanks,

解决方案

There are various bug reports around FK violations in OpenJPA when cascading remove operations to child entities:

The OpenJPA FAQ notes that the following:

Can OpenJPA reorder SQL statements to satisfy database foreign key

constraints?

Yes. OpenJPA can reorder and/or batch the SQL statements using

different configurable strategies. The default strategy is capable of

reordering the SQL statements to satisfy foreign key constraints.

However ,you must tell OpenJPA to read the existing foreign key

information from the database schema:

It would seem you can force the correct ordering of the statements by either setting the following property in your OpenJPA config

value="native(ForeignKeys=true)"/>

or by adding the org.apache.openjpa.persistence.jdbc.ForeignKey annotation to the mapping:

@OneToMany(mappedBy = "classRoom", orphanRemoval = true, cascade = CascadeType.ALL, fetch = FetchType.EAGER)

@org.apache.openjpa.persistence.jdbc.ForeignKey

protected Collection desks;

See also:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
针对你的问题,我可以给你一些指导和示例代码。首先,JPA中的CriteriaBuilder可以用于动态构建查询条件,包括多组条件的and和or组合。下面是一个示例代码,演示如何使用CriteriaBuilder查询多层嵌套一对多关系。 假设你有两个实体类,一个是User,另一个是Order,它们之间是一对多关系,即一个用户可以有多个订单: ```java @Entity public class User { @Id private Long id; private String name; @OneToMany(mappedBy = "user", cascade = CascadeType.ALL) private List<Order> orders; // getters and setters } @Entity public class Order { @Id private Long id; private String productName; private BigDecimal price; @ManyToOne @JoinColumn(name = "user_id") private User user; // getters and setters } ``` 现在,假设你要查询所有用户名为"John",且其订单中至少有一笔金额大于100的订单的用户。可以使用CriteriaBuilder构建如下查询条件: ```java public List<User> findUsersWithExpensiveOrders(String username) { CriteriaBuilder cb = entityManager.getCriteriaBuilder(); CriteriaQuery<User> cq = cb.createQuery(User.class); Root<User> userRoot = cq.from(User.class); Join<User, Order> orderJoin = userRoot.join("orders"); cq.where( cb.and( cb.equal(userRoot.get("name"), username), cb.greaterThan(orderJoin.get("price"), new BigDecimal(100)) ) ).groupBy(userRoot.get("id")).having(cb.greaterThan(cb.count(orderJoin), 0L)); TypedQuery<User> query = entityManager.createQuery(cq); return query.getResultList(); } ``` 上述代码中,我们首先使用CriteriaBuilder和CriteriaQuery创建查询对象,并从User类中获取Root作为查询的起点。然后,我们使用join方法来连接User和Order实体类,并使用equal和greaterThan方法构建多个查询条件,其中equal用于匹配用户名,greaterThan用于匹配订单金额。最后,我们使用groupBy和having方法组合查询条件,确保查询结果只包含至少有一笔金额大于100的订单的用户。 希望这个示例代码对你有所帮助。如果你还有其他问题或需要更多帮助,请随时问我。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值