jpa中orphanRemoval和cascade如何理解

jpa中orphanRemoval和cascade如何理解按照官方给出的字面意思是:如果删除关系,是否删除关系上的实体,true表示会删除,false表示不删除。我们来举个例子说明一下,现在分别有User和Address两个实体,User类上有一个addresses的字段,表示引用多个Address实例,User和Address是一对多关系。大致的代码如下:单向一对多关系测试//单向一对多,user里有addressespublicclassUser{//@OneToMany(orphanRemoval=true)//此时移除user里的某

在实际开发场景中,删除多的一方,一的一方不会被删除,一被删除了多的肯定要删除。

由此,就会使用级联操作,在一对多关系中,@Cascade属性(级联)只设置“一”的一方即可,外键由“多”的一方进行维护。

@ManyToOne和@OneToMany 注解
1.ManyToOne(多对一)单向:不产生中间表,但可以用@Joincolumn(name=” “)来指定生成外键的名字,外键在多的一方表中产生。
2.OneToMany(一对多)单向:会产生中间表,此时可以用@onetoMany @Joincolumn(name=” “)避免产生中间表,并且指定了外键的名字(别看@joincolumn在一中写着,但它存在在多的那个表中)
3.OneToMany , ManyToOne 双向(两个注解一起用的):如果不在@OneToMany中加mappedy属性就会产生中间表。

@Entity
public class Person { 
   
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int id;
    private String name;
    @OneToMany(mappedBy = "person", cascade = CascadeType.ALL)
    private List<Address> addresses;
}
  
@Entity
public class Address { 
   
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int id;
    private String street;
    private int houseNumber;
    private String city;
    private int zipCode;
    @ManyToOne(fetch = FetchType.LAZY)
    private Person person;
}

cascade属性: 指定级联操作的行为(可多选)

CascadeType.PERSIST:级联新增(又称级联保存):对A对象保存时也会对B对象进行保存。并且,只有A类新增时,会级联B对象新增。若B对象在数据库存在则抛异常。对应EntityManager的presist方法。

@Test
public void whenParentSavedThenChildSaved() { 
   
    Person person = new Person();
    Address address = new Address();
    address.setPerson(person);
    person.setAddresses(Arrays.asList(address));
    session.persist(person);
    session.flush();
    session.clear();
}
Hibernate: insert into Person (name, id) values (?, ?)
Hibernate: insert into Address (
    city, houseNumber, person_id, street, zipCode, id) values (?, ?, ?, ?, ?, ?)

CascadeType.MERGE:级联合并(级联更新):指A类新增或者变化,会级联B对象(新增或者变化)。对应EntityManager的merge方法。

@Test
public void whenParentSavedThenMerged() { 
   
    int addressId;
    Person person = buildPerson("devender");
    Address address = buildAddress(person);
    person.setAddresses(Arrays.asList(address));
    session.persist(person);
    session.flush();
    addressId = address.getId();
    session.clear();

    Address savedAddressEntity = session.find(Address.class, addressId);
    Person savedPersonEntity = savedAddressEntity.getPerson();
    savedPersonEntity.setName("devender kumar");
    savedAddressEntity.setHouseNumber(24);
    session.merge(savedPersonEntity);
    session.flush();
}
Hibernate: select address0_.id as id1_0_0_, address0_.city as city2_0_0_, address0_.houseNumber as houseNum3_0_0_, address0_.person_id as person_i6_0_0_, address0_.street as street4_0_0_, address0_.zipCode as zipCode5_0_0_ from Address address0_ where address0_.id=?
Hibernate: select person0_.id as id1_1_0_, person0_.name as name2_1_0_ from Person person0_ where person0_.id=?
Hibernate: update Address set city=?, houseNumber=?, person_id=?, street=?, zipCode=? where id=?
Hibernate: update Person set name=? where id=?

CascadeType.REMOVE:级联删除:只有A类删除时,会级联删除B类,即在设置的那一端进行删除时,另一端才会级联删除。对应EntityManager的remove方法。

@Test
public void whenParentRemovedThenChildRemoved() { 
   
    int personId;
    Person person = buildPerson("devender");
    Address address = buildAddress(person);
    person.setAddresses(Arrays.asList(address));
    session.persist(person);
    session.flush();
    personId = person.getId();
    session.clear();

    Person savedPersonEntity = session.find(Person.class, personId);
    session.remove(savedPersonEntity);
    session.flush();
}
Hibernate: delete from Address where id=?
Hibernate: delete from Person where id=?

CascadeType.REFRESH:级联刷新:获取A对象时也重新获取最新的B对象。对EntityManager的refresh(object)方法。即会重新查询数据库里的最新数据(用的比较少)

@Test
public void whenParentRefreshedThenChildRefreshed() { 
   
    Person person = buildPerson("devender");
    Address address = buildAddress(person);
    person.setAddresses(Arrays.asList(address));
    session.persist(person);
    session.flush();
    person.setName("Devender Kumar");
    address.setHouseNumber(24);
    session.refresh(person);
    
    assertThat(person.getName()).isEqualTo("devender");
    assertThat(address.getHouseNumber()).isEqualTo(23);
}

在这里,我们对保存的实体person和address进行了一些更改。当我们刷新person实体时,地址也会刷新。

CascadeType.DETACH:操作表示从持久化的上下文移除对象,当使用了CascadeType.DETACH后,子对象也会从持久化的上下文中移除。

CascadeType.ALL:级联所有操作。

orphanRemoval
之前的级联代表的都是从父操作到子操作的延伸,在写项目的时候,就遇到了这样的问题:学生选择了政治、英语课,然后修改学生课程为语文、数学。然而级联并不能做到当学生课程集合改变时,自动删除原先课程并创建新课程。这时候就需orphanRemoval了,官方文档给出的解释为:
When a target entity in one-to-one or one-to-many relationship is removed from the relationship, it is often desirable to cascade the remove operation to the target entity. Such target entities are considered “orphans,” and the orphanRemoval attribute can be used to specify that orphaned entities should be removed. For example, if an order has many line items and one of them is removed from the order, the removed line item is considered an orphan. If orphanRemovalis set to true, the line item entity will be deleted when the line item is removed from the order.
The orphanRemoval attribute in @OneToMany and @oneToOne takes a Boolean value and is by default false.

The following example will cascade the remove operation to the orphaned customer entity when it is removed from the relationship:

@OneToMany(mappedBy=“customer”, orphanRemoval=“true”)
public List getOrders() { … }

今天的文章jpa中orphanRemoval和cascade如何理解分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/23729.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注