一对多

   客户 与 联系人 一对多的关系

@Entity
@Table(name="cst_customer")
public class Customer {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="cust_id")
    private Long custId;
    @Column(name="cust_address")
    private String custAddress;
    @Column(name="cust_industry")
    private String custIndustry;
    @Column(name="cust_level")
    private String custLevel;
    @Column(name="cust_name")
    private String custName;
    @Column(name="cust_phone")
    private String custPhone;
    @Column(name="cust_source")
    private String custSource;
    //@OneToMany(targetEntity = LinkMan.class)                 对方对象的字节码对象
    //@JoinColumn(name = "lkm_cust_id",referencedColumnName = "cust_id")   
    配置客户和联系人之间的关系(一对多关系)
    @OneToMany(mappedBy = "customer",cascade = CascadeType.ALL)   
    private Set<LinkMan> linkMans = new HashSet<LinkMan>();
}
@Entity
@Table(name = "cst_linkman")
public class LinkMan {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "lkm_id")
    private Long 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 lkmMemo;//联系人备注

    @ManyToOne(targetEntity = Customer.class)  
    @JoinColumn(name = "lkm_cust_id",referencedColumnName = "cust_id")
    private Customer customer;
}

1.配置外键  获得外键维护权

@OneToMany(targetEntity = LinkMan.class)                 对方对象的字节码对象
@JoinColumn(name = "lkm_cust_id",referencedColumnName = "cust_id")   

      name:外键字段名称           referencedColumnName:  参照的主表(一的一方)的主键字段名称 

 如果在一的一方配置了外键 ,在保存操作时, 除了 两个 insert  语句, 还会多一条update语句 来维护外键关系

2.放弃外键维护权

       为了防止出现这种重复的 外键维护  一般    一的一方放弃外键维护     多的一方配置外键,且就是两条Insert语句
       mappedBy:对方配置关系的属性名称,就是多的一方的实体类中的 关联对象的 属性名
3.配置级联  cascade :   (可以配置到设置多表的映射关系的注解上)
           CascadeType.all: 所有          MERGE :更新          PERSIST :保存       REMOVE:删除

             配置了这个注解后  ,当有 更新 ,保存,删除操作时,会级联操作 关系到的表

无级联

1.主表到从表保存

    当双方都配置了外键对应关系(都有维护权)    并且没有设置级联时,需要使用两个save方法, 

     添加 主表中从表的信息  customer.getLinkMans().add(linkMan);             这时多出一条update语句  更新外键的关系

@Test
    @Transactional //配置事务
    @Rollback(false) //不自动回滚
    public void testAdd() {
        //创建一个客户,创建一个联系人
        Customer customer = new Customer();
        customer.setCustName("百度");
        LinkMan linkMan = new LinkMan();
        linkMan.setLkmName("小李");
        customer.getLinkMans().add(linkMan);
        customerDao.save(customer);
        linkManDao.save(linkMan);
    }

2.从表到主表保存

      正常的两条Insert  语句  从表中使用setCustomer  设置外键关系

@Test
    @Transactional //配置事务
    @Rollback(false) //不自动回滚
    public void testAdd1() {
        //创建一个客户,创建一个联系人
        Customer customer = new Customer();
        customer.setCustName("百度");
        LinkMan linkMan = new LinkMan();
        linkMan.setLkmName("小李");

        linkMan.setCustomer(customer);
        customerDao.save(customer);
        linkManDao.save(linkMan);
    }

3.放弃外键维护权

由于配置了多的一方到一的一方的关联关系(当保存的时候,就已经对外键赋值) 

由于配置了一的一方到多的一方的关联关系(发送一条update语句,更新外键)     所以操作就重复了  ,所以在主表中mappedBy

@Test
    @Transactional //配置事务
    @Rollback(false) //不自动回滚
    public void testAdd2() {
        //创建一个客户,创建一个联系人
        Customer customer = new Customer();
        customer.setCustName("百度");
        LinkMan linkMan = new LinkMan();
        linkMan.setLkmName("小李");

        linkMan.setCustomer(customer);
        customer.getLinkMans().add(linkMan);
        customerDao.save(customer);
        linkManDao.save(linkMan);
    }

添加级联

  只能在主表中添加级联  @OneToMany(mappedBy = "customer",cascade = CascadeType.ALL) 

    就只需要保存 客户    就会自动根据根据客户中   联系人的列表  去级联保存 联系人

@Test
    @Transactional //配置事务
    @Rollback(false) //不自动回滚
    public void testCascadeAdd() {
        Customer customer = new Customer();
        customer.setCustName("百度1");
        LinkMan linkMan = new LinkMan();
        linkMan.setLkmName("小李1");
        linkMan.setCustomer(customer);

        customer.getLinkMans().add(linkMan);
        customerDao.save(customer);
    }

      级联删除   删除客户会自动删除更客户关联的  联系人

@Test
    @Transactional //配置事务
    @Rollback(false) //不自动回滚
    public void testCascadeRemove() {
        //1.查询1号客户
        Customer customer = customerDao.findOne(1l);
        //2.删除1号客户
        customerDao.delete(customer);
    }

多对多

@Entity
@Table(name = "sys_user")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="user_id")
    private Long userId;
    @Column(name="user_name")
    private String userName;
    @Column(name="age")
    private Integer age;

    @ManyToMany(targetEntity = Role.class,cascade = CascadeType.ALL)
    @JoinTable(name = "sys_user_role",
        //joinColumns,当前对象在中间表中的外键
        joinColumns = {@JoinColumn(name = "sys_user_id",referencedColumnName = "user_id")},
        //inverseJoinColumns,对方对象在中间表的外键
        inverseJoinColumns = {@JoinColumn(name = "sys_role_id",referencedColumnName = "role_id")}
    )
    private Set<Role> roles = new HashSet<Role>();
}
@Entity
@Table(name = "sys_role")
public class Role {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "role_id")
    private Long roleId;
    @Column(name = "role_name")
    private String roleName;
    //配置多对多
    @ManyToMany(mappedBy = "roles")  //配置多表关系
    private Set<User> users = new HashSet<User>();
}

 1.声明表关系的配置
     @ManyToMany(targetEntity = Role.class)      targetEntity:代表对方的实体类字节码        

       一般被选择的的表放弃维护权     mappedBy 配置自己在关联实体类中的属性名

   2.配置中间表(包含两个外键)
    @JoinTable     name : 中间表的名称       Spring Data Jpa  会根据这个值 自动创建 一个中间表

         1.joinColumns:配置当前对象在中间表的外键   

               @JoinColumn的数组  name:外键名              referencedColumnName:参照的主表的主键名
        2.inverseJoinColumns:配置对方对象在中间表的外键

  无级联时  保存用户  角色信息              创建三个表,三个Insert语句

@Test
    @Transactional
    @Rollback(false)
    public void  testAdd() {
        User user = new User();
        user.setUserName("小李");
        Role role = new Role();
        role.setRoleName("java程序员");
        //配置用户到角色关系,可以对中间表中的数据进行维护     1-1
        user.getRoles().add(role);
        //配置角色到用户的关系,可以对中间表的数据进行维护     1-1
        role.getUsers().add(user);

        userDao.save(user);
        roleDao.save(role);
    }

添加级联时   @ManyToMany(targetEntity = Role.class,cascade = CascadeType.ALL)

 根据保存的用户的关联的角色  自动在中间表  和 角色表    添加信息,           创建三个表,三个Insert语句

//测试级联添加(保存一个用户的同时保存用户的关联角色)
    @Test
    @Transactional
    @Rollback(false)
    public void  testCasCadeAdd() {
        User user = new User();
        user.setUserName("小李");

        Role role = new Role();
        role.setRoleName("java程序员");
        //配置用户到角色关系,可以对中间表中的数据进行维护     1-1
        user.getRoles().add(role);
        //配置角色到用户的关系,可以对中间表的数据进行维护     1-1
        role.getUsers().add(user);

        userDao.save(user);
    }

级联删除    自动删除中间表 和 角色表中的信息          三条delete语句

删除id为1的用户,同时删除他的关联对象
    @Test
    @Transactional
    @Rollback(false)
    public void  testCasCadeRemove() {
        //查询1号用户
        User user = userDao.findOne(1l);
        //删除1号用户
        userDao.delete(user);
}

对象导航查询

   以上面的  一对多为列

    对象导航查询就是 通过查询出来的 一个客户(一的一方),  通过此对象 查询出 关联的 联系人 

    一往多查询 默认是延迟加载    多往一查询默认是立即加载可以通过  加载方式fetch 注解配置加载方式  ,一般使用默认就行
     EAGER   :立即加载         一般在多的一方配置
     LAZY    :延迟加载          一般在一的一方加,因为查询 一的一方时 不会立即查询出 一对多的所有数据 ,提升性能

@OneToMany(mappedBy = "customer",cascade = CascadeType.ALL,fetch =FetchType.EAGER)
@Test
    @Transactional // 解决在java代码中的no session问题
    public void  testQuery1() {
        //查询id为1的客户
        Customer customer = customerDao.getOne(1l);
        //对象导航查询,此客户下的所有联系人
        Set<LinkMan> linkMans = customer.getLinkMans();    不会查询
        for (LinkMan linkMan : linkMans) {
            System.out.println(linkMan);                 在这里才会查询
        }
    }

  多往一查询

@Test
    @Transactional // 解决在java代码中的no session问题
    public void  testQuery3() {
        LinkMan linkMan = linkManDao.findOne(2l);        在这里就查询了
        //对象导航查询所属的客户
        Customer customer = linkMan.getCustomer();   
        System.out.println(customer);
    }