jpa中一对多的级联增删改

本文介绍了JPA中一对多关系的级联增删改操作,以Customer和Contact表为例。在进行操作时,若不配置级联更新,可能会遇到瞬时态对象操作持久态对象导致的错误。正确做法是结合使用级联更新和mappedBy属性,以确保数据库中的关联关系得到正确维护。级联删除的设置也进行了讨论。

以Customer表和Contact表为例:

新增:

//一对多增加
	@Test
	public void testPersist() {
		Customer customer = new Customer();
		customer.setName("新客户");
		Contact contact = new Contact();
		contact.setName("新联系人");
		//添加双向关联关系
		customer.getContacts().add(contact);
		contact.setCustomer(customer);
		
		EntityManager em = MyJPAUtils.getEntityManager();
		EntityTransaction tx = em.getTransaction();
		tx.begin();
		em.persist(customer);//我已经在客户上配置了级联属性,所以这里直接保存customer即可
		tx.commit();
		em.close();
	}

更新:

	//一对多更新
	@Test
	public void testMerge() {
		Contact contact = new Contact();
		contact.setName("联系人4");
		
		EntityManager em = MyJPAUtils.getEntityManager();
		EntityTransaction tx = em.getTransaction();
		tx.begin();
		Customer customer = em.find(Customer.class, Integer.parseInt("1"));
		customer.getContacts().add(contact);//这一步涉及对象导航查询,所以对应的有个select语句出来
		contact.setCustomer(customer);//这一步不写的话,向数据库中插入的记录外键字段值为null
		//JPA在insert联系人对象的时候直接把customer_id一起插进去了,不会在insert之后出update语句,hibernate则是先insert再update一下
		tx.commit();
		em.close();
	}
在这个测试里,如果我不配置级联更新,也不配置mappedBy,那么主表会去维护关联关系,最后看到维护关联关系的
contact.setCustomer(customer);

时,会发现一个瞬时态的对象操作一个持久态对象,报错!如果不配置级联更新,但是配置了mappedBy,这时候主表放弃维护关联关系,并不会去数据库执行什么操作,不会报错,但是更新目的同时也没达到。(这里注意,contact.setCustomer(customer)这么写是不会报错的,但是如果真的需要去数据库里做对应操作那么执行到这里会报错)。

    所以正确的解决办法是,同时加上级联更新和mappeBy属性!


级联删除:

//一对多删除
	@Test
	public void testRemove() {
		EntityManager em = MyJPAUtils.getEntityManager();
		EntityTransaction tx = em.getTransaction();
		tx.begin();
		Customer c = em.find(Customer.class, Integer.parseInt("3"));
		em.remove(c);
		tx.commit();
		em.close();
	}
从表数据都可以随便删。对于主表,配置了级联删除的时候,连从表数据一块儿删;如果没配置级联删除,当从表没对应数据的时候,能正常删除,若从表有对应数据,删除失败!


在Java持久化API(JPA)中实现一对关系,通常涉及两个实体类,其中一个实体包含对另一个实体的引用集合。以下是一个详细的实现方法,涵盖实体类的定义、注解配置以及相关的持久化操作。 ### 实体类定义 在一对关系中,通常一个父实体(如 `Order`)可以包含个子实体(如 `OrderItem`)。为了实现这种关系,需要使用 `@OneToMany` 注解来标记父实体中的集合属性,并通过 `@JoinColumn` 指定外键字段。 #### 父实体 `Order` ```java import javax.persistence.*; import java.util.HashSet; import java.util.Set; @Entity @Table(name = "orders") public class Order { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String orderId; private Float amount; @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY) @JoinColumn(name = "order_id") // 外键字段 private Set<OrderItem> items = new HashSet<>(); // Getter 和 Setter 方法 public void addOrderItem(OrderItem item) { items.add(item); } } ``` #### 子实体 `OrderItem` ```java import javax.persistence.*; @Entity @Table(name = "order_items") public class OrderItem { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String productName; private Float sellPrice; // Getter 和 Setter 方法 } ``` ### 持久化操作 在 JPA 中,持久化一对关系时,需要确保父实体和子实体都正确地被保存。以下是一个使用 `EntityManager` 的示例代码,展示如何保存一个包含个订单项的订单。 ```java import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; public class JPA_OnetoManyTest { @Test public void save() { EntityManagerFactory factory = Persistence.createEntityManagerFactory("mengya"); EntityManager em = factory.createEntityManager(); em.getTransaction().begin(); Order order = new Order(); order.setOrderId("200910120001"); order.setAmount(450f); OrderItem item1 = new OrderItem(); item1.setProductName("篮球"); item1.setSellPrice(220f); OrderItem item2 = new OrderItem(); item2.setProductName("排球"); item2.setSellPrice(230f); order.addOrderItem(item1); order.addOrderItem(item2); em.persist(order); em.getTransaction().commit(); em.close(); factory.close(); } } ``` ### 数据库表结构 在数据库中,通常会为父实体和子实体分别创建表,并通过外键关。例如: - `orders` 表包含订单的基本信息。 - `order_items` 表包含订单项的信息,并通过 `order_id` 外键关到 `orders` 表。 ```sql CREATE TABLE orders ( id BIGINT PRIMARY KEY AUTO_INCREMENT, order_id VARCHAR(255), amount FLOAT ); CREATE TABLE order_items ( id BIGINT PRIMARY KEY AUTO_INCREMENT, product_name VARCHAR(255), sell_price FLOAT, order_id BIGINT, FOREIGN KEY (order_id) REFERENCES orders(id) ); ``` ### 级联操作 在 `@OneToMany` 注解中,可以通过 `cascade` 属性指定级联操作。例如,设置 `cascade = CascadeType.ALL` 表示当父实体被保存、更新或删除时,相关的子实体也会被级联操作。 ### 获取数据 在获取父实体时,可以通过 `fetch` 属性控制是否立即加载关的子实体。例如,`fetch = FetchType.LAZY` 表示延迟加载,只有在访问子实体集合时才会执行查询。 ### 总结 在 JPA 中实现一对关系的关键在于正确使用 `@OneToMany` 和 `@JoinColumn` 注解,并确保父实体和子实体之间的关关系在代码中正确维护。通过合理的级联操作和获取策略,可以有效地管理数据的持久化和查询操作。
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值