Spring Data JPA的多表操作

Spring Data JPA的多表操作

  1. 一对多关系
    案例:客户和联系人(客户:公司;一个客户可以具有多个联系人,一个联系人只从属于一家公司)
    步骤:
    1. 明确表关系

      一对多

    2. 确定表关系(外键|中间表)

      客户表是主表,联系人表是从表,在从表上添加外键,指向主表的主键

    3. 编写实体类,在实体类中描述表关系(包含关系)

      客户实体类:在客户的实体类中包含联系人的集合

      联系人实体类:在联系人实体类包含客户的对象

    4. 配置映射关系

      使用jpa注解配置一对多映射关系

    import javax.persistence.*;
    import java.util.HashSet;
    import java.util.Set;
    
    @Entity
    @Table(name = "customer")
    public class Customer {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Column(name = "id")
        private Integer id;
        @Column(name = "address")
        private String address;
        @Column(name = "industry")
        private String industry;
        @Column(name = "level")
        private String level;
        @Column(name = "name")
        private String name;
        @Column(name = "phone")
        private String phone;
        @Column(name = "source")
        private String source;
    
        //配置客户和联系人的关系,一对多关系(包含关系)
        /*
         * 使用注解配置多表关系
         *   1.声明关系
         *      @OneToMany:一对多关系
         *         targetEntity:对方对象的字节码对象
         *   2.配置外键|中间表
         *      @JoinColumn:配置外键
         *          name:外键名称
         *          referencedColumnName:参照的主表的主键名称
         *  在客户的实体类上(一的一方)添加了外键的配置,所以对用户而言,具备了维护外键的作用
         * */
        @OneToMany(targetEntity = LinkMan.class)
        @JoinColumn(name = "fk",referencedColumnName = "id")
        private Set<LinkMan> linkMans = new HashSet<LinkMan>();
    
    	//setter and getter
        //toString
    }
    
    
    import javax.persistence.*;
    
    @Entity
    @Table(name = "linkman")
    public class LinkMan {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Column(name = "lkm_id")
        private Integer lkmid;
        @Column(name = "lkm_name")
        private String lkmname;
        @Column(name = "lkm_gender")
        private String lkmgender;
        @Column(name = "lkm_phone")
        private String lkmphone;
        @Column(name = "lkm_mobile")
        private String lkmmobile;
        @Column(name = "lkm_email")
        private String lkmemail;
        @Column(name = "lkm_position")
        private String lkmposition;
        @Column(name = "lkm_memo")
        private String lkmmeno;
    
        /*
        * 配置联系人到客户的多对一关系
        *   使用注解的形式配置多对一关系
        *       1.配置表关系
        *           @ManyToOne:配置多对一关系
        *       2.配置外键|中间表
        *           name:外键名称
        *           referencedColumnName:参照的主表的主键名称
        *
        * */
        @ManyToOne(targetEntity = Customer.class)
        @JoinColumn(name = "fk",referencedColumnName = "id")
        private Customer customer;
    
        //setter and getter
        //toString
    }
    
    

    测试代码

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations = "classpath:applicationContext.xml")
    public class OneToManyTest {
    
        @Resource
        private CustomerDao customerDao;
        @Resource
        private LinkManDao linkManDao;
    
        /*
        * 保存一个客户,保存一个联系人
        * */
        @Test
        @Transactional
        @Rollback(false)  //不自动回滚
        public void testAdd(){
            //创建客户,创建联系人
            Customer customer = new Customer();
            customer.setName("百度");
    
            LinkMan linkMan = new LinkMan();
            linkMan.setLkmname("李彦宏");
    
            //配置两个实体类的关系
            customer.getLinkMans().add(linkMan);//也可以linkMan.setCustomer(customer);
    
            customerDao.save(customer);
            linkManDao.save(linkMan);
    
        }
    }
    
    

    当两个实体类进行相互的配置关系时(即双方都配置),会出现多余的update语句,需要一的一方放弃外键维护权

    //    @OneToMany(targetEntity = LinkMan.class)
    //    @JoinColumn(name = "fk",referencedColumnName = "id")
    //mappedBy 对方配置的属性的名称
    @OneToMany(mappedBy  = "customer")
    private Set<LinkMan> linkMans = new HashSet<LinkMan>();
    

    级联操作:

    1.需要区分操作主体

    2.需要在操作主题的实体类上,添加级联属性(需要添加到多表映射关系的注解上)

    3.cascade(配置级联)

    级联添加

    /*
        * 级联添加,保存一个客户的同时,保存客户的所有联系人
        *   需要在操作主题的实体类上配置cascade属性
        * */
    @Test
    @Transactional
    @Rollback(false)  //不自动回滚
    public void testCasCade(){
        //创建客户,创建联系人
        Customer customer = new Customer();
        customer.setName("百度1");
    
        LinkMan linkMan = new LinkMan();
        linkMan.setLkmname("李彦宏1");
    
        //配置两个实体类的关系
        customer.getLinkMans().add(linkMan);  //也可以linkMan.setCustomer(customer);
        linkMan.setCustomer(customer);
    
        customerDao.save(customer);
        linkManDao.save(linkMan);
    
    }
    

    ​ 客户实体类

    @OneToMany(mappedBy = "customer",cascade = CascadeType.ALL)  //级联所有操作
    private Set<LinkMan> linkMans = new HashSet<LinkMan>();
    

    级联删除

    *
         * 级联删除,删除1号客户的同时,删除1号客户的所有联系人
         *   需要在操作主题的实体类上配置cascade属性
         * */
        @Test
        @Transactional
        @Rollback(false)  //不自动回滚
        public void testCasCadeRemove(){
        //查询1号客户
        Customer customer = customerDao.findOne(1);
        //删除1号客户
        customerDao.delete(customer);
    
    }
    

    ​ 客户实体类

    @OneToMany(mappedBy = "customer",cascade = CascadeType.ALL)  //级联所有操作private Set<LinkMan> linkMans = new HashSet<LinkMan>();
    
    注意:配置文件中注入jpa的配置信息
    <!--注入jpa的配置信息-->
    <property name="jpaProperties">
        <props>
            <prop key="hibernate.hbm2ddl.auto">update</prop>
        </props>
    </property>
    
  2. 多对多关系
    案例:用户和角色以及级联的添加
    @Entity
    @Table(name = "sys_user")
    public class User {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Column(name = "userid")
        private Integer userid;
        @Column(name = "username")
        private String username;
        @Column(name = "userage")
        private Integer userage;
        /*
        * 配置用户到角色的多对多关系
        *   配置多对多关系
        *       1.声明表关系配置
        *           @ManyToMany 多对多
        *               targetEntity:代表对方的实体类字节码
        *       2.配置中间表(包含两个外键)
        *           @JoinTable
        *               name:中间表名
        *
        * */
        @ManyToMany(targetEntity = Role.class,cascade = CascadeType.ALL)
        @JoinTable(name = "sys_user_role",
                //joinColumns:当前对象在中间表的外键;referencedColumnName:外键来源于user实体类的主键userid
                joinColumns = {@JoinColumn(name = "fk_userid",referencedColumnName = "userid")},
                //inverseJoinColumns中间对象在中间表的外键
                inverseJoinColumns = {@JoinColumn(name = "fk_roleid",referencedColumnName = "roleid")})
        private Set<Role> roles = new HashSet<Role>();
    
        //setter and getter
        //toString
    }
    
    
    @Entity
    @Table(name = "sys_role")
    public class Role {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Column(name = "roleid")
        private Integer roleid;
        @Column(name = "rolename")
        private String rolename;
        /*
        * 配置角色到用户的多对多关系
        *  放弃维护权:mappedBy对方配置映射关系的属性名称
        * */
        @ManyToMany(mappedBy = "roles")
        private Set<User> users = new HashSet<User>();
    
        //setter and getter
        //toString
    }
    

    接口

    public interface UserDao extends JpaRepository<User,Integer>, JpaSpecificationExecutor<User> {
    }
    
    public interface RoleDao extends JpaRepository<Role,Integer>, JpaSpecificationExecutor<Role> {
    }
    

    测试类

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations = "classpath:applicationContext.xml")
    public class ManyToManyTest {
    
        @Resource
        UserDao userDao;
        @Resource
        RoleDao roleDao;
    
        /*
        * 多对多放弃维护权,被动的一方放弃
        * */
        @Test
        @Transactional
        @Rollback(false)
        public void manyToMany(){
            User user = new User();
            user.setUsername("老王");
    
            Role role = new Role();
            role.setRolename("程序员");
    
            //配置用户到角色的关系,可以对中间表的数据进行维护
            user.getRoles().add(role);
            //配置角色到用户的关系,可以对中间表的数据进行维护
            role.getUsers().add(user);
    
            userDao.save(user);
            roleDao.save(role);
        }
    
        /*
         *测试级联的添加(保存用户的同时保存用户的关联角色)
         * */
        @Test
        @Transactional
        @Rollback(false)
        public void casCade(){
            User user = new User();
            user.setUsername("老王1");
    
            Role role = new Role();
            role.setRolename("程序员1");
    
            //配置用户到角色的关系,可以对中间表的数据进行维护
            user.getRoles().add(role);
            //配置角色到用户的关系,可以对中间表的数据进行维护
            role.getUsers().add(user);
    
            userDao.save(user);
        }
    }
    
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Spring Data JPA可以通过使用@Query注解和JPQL语句来实现多表联合查询。在JPQL语句中,可以使用JOIN关键字来连接多个,并使用ON子句来指定连接条件。例如: @Query("SELECT u.username, p.title FROM User u JOIN u.posts p ON u.id = p.userId") List<Object[]> findUserAndPost(); 这个例子中,User和Post是两个实体类,它们之间通过userId属性建立了关联关系。通过JOIN关键字和ON子句,我们可以将两个连接起来,并查询出用户名和文章标题。最终返回的是一个Object数组,包含了查询结果中的两个字段。 除了使用@Query注解,Spring Data JPA还提供了一些方法命名规则,可以自动生成查询语句。例如,如果我们在UserRepository中定义一个方法: List<User> findByPostsTitle(String title); Spring Data JPA会自动根据方法名生成查询语句,查询所有标题为指定值的文章所属的用户。这个方法名中的“Posts”是User实体类中的一个属性,它用户的所有文章。通过这种方式,我们可以方便地进行多表联合查询,而不需要手动编写复杂的SQL语句。 ### 回答2: Spring Data JPASpring Framework的一个模块,它提供了SpringJPA之间的集成,并支持快速开发具有CRUD功能的应用程序。在多表联合查询中,Spring Data JPA可以使用JPQL或原生SQL语句来查询多个,并通过实体类的关系来建立之间的关联。下面将具体介绍如何使用Spring Data JPA进行多表联合查询。 1. 使用JPQL进行多表联合查询 使用JPQL进行多表联合查询比使用原生SQL语句更方便,因为可以直接使用实体类和属性名来代替名和列名。 例如,我们有两个实体类:Customer和Order,它们之间是多对一的关系,即一个客户可以下多个订单。我们可以使用以下JPQL查询语句来查询所有客户及其对应的订单: ``` @Query("SELECT c, o FROM Customer c LEFT JOIN c.orders o") List<Object[]> findCustomerWithOrder(); ``` 这里使用了LEFT JOIN关键字来连接两个,LEFT JOIN示左连接,即返回左(这里是Customer)中所有数据和右(这里是Order)中匹配的数据。在SELECT语句中,我们选择了两个实体类,分别用c和o来代它们,并将它们放在一个数组中返回。这样就可以查询到所有客户及其对应的订单。 2. 使用原生SQL语句进行多表联合查询 如果使用JPQL不能满足需求,也可以使用原生SQL语句来进行多表联合查询。这时需要使用EntityManager来执行SQL语句。 例如,我们有两个:Customer和Order,它们之间的关系同上。我们可以使用以下SQL语句来查询所有客户及其对应的订单: ``` SELECT c.*, o.* FROM customer c LEFT JOIN orders o ON c.id = o.customer_id ``` 在EntityManager中,可以使用createNativeQuery方法来创建原生SQL语句的查询对象,以及setParameter方法来设置查询参数(如果有的话)。例如: ``` String sql = "SELECT c.*, o.* FROM customer c LEFT JOIN orders o ON c.id = o.customer_id"; Query query = entityManager.createNativeQuery(sql); List<Object[]> resultList = query.getResultList(); ``` 这里使用了Query.getResultList方法来返回结果集,它返回的是一个包含多个数组的列,每个数组对应一行查询结果。数组中的元素按照SELECT语句的顺序排列。 总结 Spring Data JPA提供了方便的方法来进行多表联合查询,可以使用JPQL或原生SQL语句来查询多个,并通过实体类之间的关系建立之间的关联。使用JPQL可以更方便地查询,而使用原生SQL语句可以更灵活地满足各种查询需求。 ### 回答3: Spring Data JPASpring Data项目的一部分,它通过JPA规范提供了ORM解决方案。在关系型数据库中,一个数据库通常由多张组成,而在开发过程中,我们经常需要对这些进行查询、修改、删除等操作,如果我们需要进行多表查询,该如何实现呢? Spring Data JPA 提供了多种方式实现多表联合查询,下面我们对这些方式进行一一介绍。 1.通过JPA的关联查询实现多表联合 JPA提供了两种形式的关联查询:内部关联查询和左外关联查询,这两种关联查询可以满足大部分复杂查询的需求。 内部关联查询:通过@Table注解中@TableJoinColumn属性或@JoinColumn注解,将两个实体类之间的关联关系定义在Java类中。定义完关联关系后,可以通过JPQL或Spring Data JPA提供的函数查询方法实现联合查询。 左外关联查询:Spring Data JPA还提供了@Query注解的方式,开发者可以自行编写JPQL或SQL语句实现多表联合查询,并通过@Query注解进行绑定。 2.通过Criteria API实现多表联合 Criteria API是JPA提供的查询语言的一种形式,它允许开发人员通过程序生成查询语句,而不必编写具体的SQL或JPQL语句。使用Criteria API时,只需要将实体类的基本属性与关联属性设定好之后,生成一个CriteriaBuilder对象,就可以构建复杂的查询语句。 3.通过Spring Data JPA提供的命名查询实现多表联合 Spring Data JPA提供了命名查询的方式,命名查询是通过在Repository中定义方法的名称和方法的输入参数来实现的。命名查询是一个声明式的查询,开发者可以指定所需的查询字符串和返回值。 总而言之,Spring Data JPA提供了多种方式实现多表联合查询,并且具有简洁、高效、易维护等特点,开发者可以根据需求选择最合适的方式来实现多表联合查询。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值