JPA的单向或双向一对一多对多使用和配置

JPA的一对多和多对多配置实战
本文详细介绍了JPA中单向和双向的一对多、多对多关系配置,包括保存、查询、级联操作和孤儿删除。强调了在实际应用中,如何选择List和Set集合类型,以及级联和孤儿删除策略的重要性。

1 单向的一对多

1.1 配置
多方

@Entity@Table(name="t_product")
public class Product {   
    @Id    
    @GeneratedValue   
    private Long id;   
    private String name;
}

1方配置

@Entity
@Table(name="t_productDir")
public class ProductDir {
    @Id
    @GeneratedValue
    private Long id;
    private  String name;
    //泛型必须添加进去
    @OneToMany
    @JoinColumn(name="dir_id")
    private Set<Product> products = new HashSet<>();
 }

1.2 保存
无论怎么保存,都在额外发送sql (所有一般不用单向一对多)

1.3 查询
lazy加载

//现在使用 Set集合 HashSet 打印出来 PersistentSet
//PersistentSet 它是Set的实现类 和 HashSet一样 ,PersistentSet 和 HashSet都是
//Set的实现类,是兄弟关系 --在定义实体的集合的时候,不要定义HashSet
//PersistentBag 也是 List的实现类,和ArrayList一样,ArrayList和PersistentBag都是
//List的实现 ,是兄弟关系 --在定义实体的集合的时候,不要定义ArrayList

总结:在定义实体类的时候时候,如果使用到集合,就使用集合接口的方式
1.4集合的使用
现在在定义集合的时候,什么情况下使用List ,什么情况下使用Set?

List/Set区别?

​ List是有序 可以重复 Set 无顺序,不能重复

Set 一般使用在多对多 或者 一对多

List 一般组合 一般使用单据上面

1.5 集合排序 orderby
配置

@OneToMany
@JoinColumn(name = "dir_id")
@OrderBy("price DESC")       
private List<ProductSet> products = new ArrayList<ProductSet>();  = new HashSet<ProductSet>(); 

2 双向的一对多 或者 多对一

配置:尽量让多方来维护的关系,一方放弃管理mappedBy

    @OneToMany(mappedBy = "dir")
    private List<Product> products = new ArrayList<>();

2.1级联操作保存
级联:就是我操作一方数据,就同时可以多方的数据也一并操作

persist(dir);

级联分为:级联保存 级联删除

@OneToMany(cascade = CascadeType.PRESIST)
2.2 级联删除

@OneToMany(cascade = CascadeType.REMOVE)

2.3 孤儿删除

让一方解除关系 ,才能从1方删除多方

@OneToMany(cascade = CascadeType.REMOVE,mappedBy = "dir",orphanRemoval = true)

2.4 强级联 --项目里使用 组合关系(单据)
@OneToMany(cascade = CascadeType.ALL,mappedBy = “dir”,orphanRemoval = true)

3 单向多对多

3.1单向多对多配置

多对多

​ 用户 和 角色

一个用户可以拥有多个角色 比如 强哥 用来 管理员角色 学生角色

一个角色 可以拥有多个用户 比如 管理员角色 有 强哥或者航哥
​ User

@Entity
@Table(name="t_user")
public class User {
    @Id
    @GeneratedValue
    private Long id;
    private String name;
    @ManyToMany
    @JoinTable(name="t_user_role",joinColumns={@JoinColumn(name="user_id")},
            inverseJoinColumns ={@JoinColumn(name="role_id")} )
    private Set<Role> roles = new HashSet<>();
}

Role

@Entity
@Table(name="t_role")
public class Role {   
    @Id    @GeneratedValue    
    private Long id;    
    private String name;
}

3.2 单向对多对保存数据
保存代码

 //3个用户 2个角色
        User user1 = new User();
        user1.setName("渣渣辉");

        User user2 = new User();
        user2.setName("光头强");

        User user3 = new User();
        user3.setName("王天霸");
        Role role1 = new Role();
        role1.setName("演员");
        Role role2 = new Role();
        role2.setName("导演");

        //设置关系
        user1.getRoles().add(role1);
        user2.getRoles().add(role1);
        user3.getRoles().add(role1);
        user1.getRoles().add(role2);
        user2.getRoles().add(role2);

        //保存数据
        EntityManager entityManager = JpaUtils.getEntityManager();
        entityManager.getTransaction().begin();
        entityManager.persist(user1);
        entityManager.persist(user2);
        entityManager.persist(user3);
        entityManager.persist(role1);
        entityManager.persist(role2);

        entityManager.getTransaction().commit();

查询:如果要使用lazy加载 自己配置lazy就可以

4 双向多对多

4.1配置

role这方

@ManyToMany(fetch = FetchType.LAZY,cascade = CascadeType.REMOVE)
    @JoinTable(name="t_user_role",joinColumns={@JoinColumn(name="role_id")},
            inverseJoinColumns ={@JoinColumn(name="user_id")} )
    private Set<User> users = new HashSet<>();

user这方

 @ManyToMany(fetch = FetchType.LAZY,cascade = CascadeType.REMOVE)
    @JoinTable(name="t_user_role",joinColumns={@JoinColumn(name="user_id")},
            inverseJoinColumns ={@JoinColumn(name="role_id")} )
    private Set<Role> roles = new HashSet<>();

4.2操作
(1)级联保存:

user配置级联保存

   EntityManager entityManager = JpaUtils.getEntityManager();
        entityManager.getTransaction().begin();
        entityManager.persist(user1);
        entityManager.persist(user2);
        entityManager.persist(user3);

        entityManager.getTransaction().commit();

(2)删除1 先删除中间表,再删除user1

 //保存数据
 EntityManager entityManager = JpaUtils.getEntityManager();
 User user = entityManager.find(User.class, 1L);
 entityManager.getTransaction().begin();
 entityManager.remove(user);
 entityManager.getTransaction().commit();

(3)删除2 删除user1的所有包含角色(role1,role2),不能删除user1(只删除中间表)

//保存数据
EntityManager entityManager = JpaUtils.getEntityManager();
User user = entityManager.find(User.class, 1L);
entityManager.getTransaction().begin();
user.getRoles().clear();
entityManager.getTransaction().commit();

(4)删除user1的一个角色,不能删除user1(只删除中间表)

 //保存数据
 EntityManager entityManager = JpaUtils.getEntityManager();
 User user1 = entityManager.find(User.class, 1L);
 Role role1 = entityManager.find(Role.class, 1L);
 entityManager.getTransaction().begin();
 user1.getRoles().remove(role1);
 entityManager.getTransaction().commit();

(5)删除 用户3的角色1 添加用户3的角色2

 @Test
    public void testDelete4()throws Exception{
        //保存数据
        EntityManager entityManager = JpaUtils.getEntityManager();
        User user3 = entityManager.find(User.class, 3L);
        Role role1 = entityManager.find(Role.class, 1L);
        Role role2 = entityManager.find(Role.class, 2L);
        entityManager.getTransaction().begin();
        user3.getRoles().remove(role1);
        user3.getRoles().add(role2);
        entityManager.getTransaction().commit();
    }

(5)级联删除

配置

   @ManyToMany(fetch = FetchType.LAZY,cascade = CascadeType.REMOVE)
    @JoinTable(name="t_user_role",joinColumns={@JoinColumn(name="user_id")},
            inverseJoinColumns ={@JoinColumn(name="role_id")} )

代码: 把user3 删除 相关的角色删除 在中间表相关的数据删除

 @Test
    public void testDelete5()throws Exception{
        //保存数据
        EntityManager entityManager = JpaUtils.getEntityManager();
        User user3 = entityManager.find(User.class, 3L);
        entityManager.getTransaction().begin();
        entityManager.remove(user3);
        entityManager.getTransaction().commit();

    }

5 一对一

一对一 可以看成 一对多 或者 多对一的特殊情况

一对一场景:

​ QQ 和 QQZone

一般使用多对1来代替一对一

关于重点配置的建议:

​ (1)建议使用单向 多 对一 不要使用单向一对多

​ (2)如果要使用1对多,尽量使用双向配置,让1方放弃管理

(3) 多对多 如果想相互获取数据 配置双向,如果单向操作 就配置单向

(4) 使用 多对一 来代替一对一 ,如果实在使用一对一 使用唯一外键的方式

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值