JPA入门02-关联关系

映射单向多对一的关联关系

Customer

@Table(name = "customer2")
@Entity
public class Customer {

    private Integer id;
    private String lastName;
    private String email;
    private int age;
    private Date createdTime;
    private Date birth;

        .......
}

Order

@Table(name = "order2")
@Entity
public class Order {

    private Integer id;
    private String orderName;
    private Customer customer;

    /**
     *  映射单向多对一的关联关系:
     *      1.使用@ManyToOne
     *      2.使用JoinColumn来映射外键
     *          使用name属性来映射外键列的字段名
     *      3.可使用 @ManyToOne 的 fetch 属性来修改默认的关联属性的加载策略
     */
    @ManyToOne
    @JoinColumn(name = "customer_id")
    public Customer getCustomer() {
        return customer;
    }
}

测试

    /**
     * 保存多对一时, 建议先保存 1 的一端, 后保存多的一端, 这样不会多出额外的 UPDATE 语句.
     */
    @Test
    public void testManyToOnePersist() {
        Customer customer = new Customer();
        customer.setAge(18);
        customer.setBirth(new Date());
        customer.setCreatedTime(new Date());
        customer.setEmail("gg@163.com");
        customer.setLastName("GG");

        Order order1 = new Order();
        order1.setOrderName("G-GG-1");

        Order order2 = new Order();
        order2.setOrderName("G-GG-2");

        //设置关联关系
        order1.setCustomer(customer);
        order2.setCustomer(customer);

        //执行保存操作
        entityManager.persist(customer);

        entityManager.persist(order1);
        entityManager.persist(order2);


    }

    //默认情况下, 使用左外连接的方式来获取 n 的一端的对象和其关联的 1 的一端的对象.
    //可使用 @ManyToOne 的 fetch 属性来修改默认的关联属性的加载策略
    @Test
    public void testManyToOneFind(){
        Order order = entityManager.find(Order.class, 1);
        System.out.println(order.getOrderName());

        System.out.println(order.getCustomer().getLastName());
    }

    //不能直接删除 1 的一端, 因为有外键约束.
    @Test
    public void testManyToOneRemove(){

        //可以直接删除多的一端
//      Order order = entityManager.find(Order.class, 1);
//      entityManager.remove(order);

        Customer customer = entityManager.find(Customer.class, 7);
        entityManager.remove(customer);
    }

    @Test
    public void testManyToOneUpdate(){
        Order order = entityManager.find(Order.class, 2);
        order.getCustomer().setLastName("FFF");
    }

映射单向一对多的关联关系(跟前面是类似的)

Customer

@Table(name = "customer2")
@Entity
public class Customer2 {

    private Integer id;
    private String lastName;
    private String email;
    private int age;
    private Date createdTime;
    private Date birth;

    private Set<Order> orders = new HashSet<>();

    <!--
        使用 @OneToMany 来映射 1-n 的关联关系
        使用 @JoinColumn 来映射外键列的名称
        可以使用 @OneToMany 的 fetch 属性来修改默认的加载策略
        这里的外键还是在多的一方生成的
        可以通过 @OneToMany 的 cascade 属性来修改默认的删除策略. 
    -->
    @OneToMany
    @JoinColumn(name = "customer_id")
    public Set<Order> getOrders() {
        return orders;
    }

Order

@Table(name = "order2")
@Entity
public class Order2 {

    private Integer id;
    private String orderName;
      .......
}

测试

    //单向 1-n 关联关系执行保存时, 一定会多出 UPDATE 语句.
    //因为 n 的一端在插入时不会同时插入外键列. 
    @Test
    public void testOneToManyPersist(){
        Customer customer = new Customer();
        customer.setAge(18);
        customer.setBirth(new Date());
        customer.setCreatedTime(new Date());
        customer.setEmail("mm@163.com");
        customer.setLastName("MM");

        Order order1 = new Order();
        order1.setOrderName("O-MM-1");

        Order order2 = new Order();
        order2.setOrderName("O-MM-2");

        //建立关联关系
        customer.getOrders().add(order1);
        customer.getOrders().add(order2);

        order1.setCustomer(customer);
        order2.setCustomer(customer);

        //执行保存操作
        entityManager.persist(customer);

        entityManager.persist(order1);
        entityManager.persist(order2);
    }


    //默认对关联的多的一方使用懒加载的加载策略. 
    //可以使用 @OneToMany 的 fetch 属性来修改默认的加载策略
    @Test
    public void testOneToManyFind(){
        Customer customer = entityManager.find(Customer.class, 9);
        System.out.println(customer.getLastName());

        System.out.println(customer.getOrders().size());
    }


    //默认情况下, 若删除 1 的一端, 则会先把关联的 n 的一端的外键置空, 然后进行删除. 
    //可以通过 @OneToMany 的 cascade 属性来修改默认的删除策略. 
    @Test
    public void testOneToManyRemove(){
        Customer customer = entityManager.find(Customer.class, 8);
        entityManager.remove(customer);
    }

    @Test
    public void testUpdate(){
        Customer customer = entityManager.find(Customer.class, 10);

        customer.getOrders().iterator().next().setOrderName("O-XXX-10");
    }

映射双向多对一的关联关系()

双方默认都维护外键(外键在多的一方)

Customer

@Table(name="JPA_CUTOMERS")
@Entity
public class Customer {

    private Integer id;
    private String lastName;
    private String email;
    private int age;
    private Date createdTime;
    private Date birth;

    private Set<Order> orders = new HashSet<>();

    //映射单向 1-n 的关联关系
    //使用 @OneToMany 来映射 1-n 的关联关系
    //使用 @JoinColumn 来映射外键列的名称(外键在多的一方)
    //可以使用 @OneToMany 的 fetch 属性来修改默认的加载策略
    //可以通过 @OneToMany 的 cascade 属性来修改默认的删除策略. 
    //注意当使用mapperBy时说明已经放弃维护外键,那么维护外键的@JoinColumn就应该删掉了

    @JoinColumn(name="CUSTOMER_ID")
    @OneToMany(fetch=FetchType.LAZY,cascade={CascadeType.REMOVE})
    public Set<Order> getOrders() {
        return orders;
    }

    ..........

}

Order

@Table(name="JPA_ORDERS")
@Entity
public class Order {

    private Integer id;
    private String orderName;

    private Customer customer;

    //映射单向 n-1 的关联关系
    //使用 @ManyToOne 来映射多对一的关联关系
    //使用 @JoinColumn 来映射外键. 
    //可使用 @ManyToOne 的 fetch 属性来修改默认的关联属性的加载策略

    @JoinColumn(name="CUSTOMER_ID")
    @ManyToOne(fetch=FetchType.LAZY)
    public Customer getCustomer() {
        return customer;
    }

    .......
}

测试

    //若是双向 1-n 的关联关系, 执行保存时
    //因为双方都维护外键所以肯定有多余的sql语句,所以我们需要由一方放弃维护
    //双向1-多关联关系,建议放弃1的一方维护外键(学生记老师的名字比老师记学生的要方便)
    //放弃维护关联关系:使用 @OneToMany中的mapperBy属性,属性值name="多的一方中本类的引用"
    //注意:如果使用 mappedBy 属性并指明让谁来维护外键,所以自己维护外键的JoinColumn要删除

        @Test
    public void testOneToManyPersist(){
        Customer customer = new Customer();
        customer.setAge(18);
        customer.setBirth(new Date());
        customer.setCreatedTime(new Date());
        customer.setEmail("mm@163.com");
        customer.setLastName("MM");

        Order order1 = new Order();
        order1.setOrderName("O-MM-1");

        Order order2 = new Order();
        order2.setOrderName("O-MM-2");

        //建立关联关系
        customer.getOrderSet().add(order1);
        customer.getOrderSet().add(order2);

        order1.setCustomer(customer);
        order2.setCustomer(customer);

        //执行保存操作
        entityManager.persist(customer);

        entityManager.persist(order1);
        entityManager.persist(order2);
    }


    //双向关联find()方法默认都是懒加载
    //可以使用 @OneToMany 的 fetch 属性来修改默认的加载策略
    @Test
    public void testOneToManyFind(){
        Customer customer = entityManager.find(Customer.class, 2);
        System.out.println(customer.getLastName());
        System.out.println("---------------------");

        System.out.println(customer.getOrderSet().size());

        System.out.println("+++++++++++++++++++++++++++++++");
        Order order = entityManager.find(Order.class, 2);
        System.out.println(order.getOrderName());
        System.out.println("------------------------");
        System.out.println(order.getCustomer());
    }


    //默认情况下, 若删除 1 的一端, 则会先把关联的 n 的一端的外键置空, 然后进行删除.
    //但是如果要删除的哪一方放弃了外键维护那么就删除不了会报错(外键约束)
    @Test
    public void testOneToManyRemove(){
        Customer customer = entityManager.find(Customer.class, 1);
        entityManager.remove(customer);
    }


    @Test
    public void testUpdate(){
        Customer customer = entityManager.find(Customer.class, 2);

        customer.getOrderSet().iterator().next().setOrderName("dddd");
//        customer.getOrderSet().iterator().next().setOrderName("O-XXX-10");
    }

映射双向一对一的关联关系

Manager

@Table(name = "managers")
@Entity
public class Manager {

    private Integer id;
    private String name;
    private Department department;

    //不维护外键(即该表中没有外键)
    @OneToOne(mappedBy = "manager")
    public Department getDepartment() {
        return department;
    }

}

DepartMent

@Table(name = "department")
@Entity
public class Department {

    private Integer id;
    private  String deptName;
    private Manager manager;

    @OneToOne()
    @JoinColumn(name = "user_id",unique = true)
    public Manager getManager() {
        return manager;
    }
}    

测试

    //双向 1-1 的关联关系, 建议先保存不维护关联关系的一方, 即没有外键的一方, 这样不会多出 UPDATE 语句.
    @Test
    public void testOneToOnePersistence(){
        Manager mgr = new Manager();
        mgr.setName("M-BB");

        Department dept = new Department();
        dept.setDeptName("D-BB");

        //设置关联关系
        mgr.setDepartment(dept);
        dept.setManager(mgr);

        //执行保存操作
        entityManager.persist(mgr);
        entityManager.persist(dept);
    }

    //1. 默认情况下, 若获取不维护关联关系的一方, 则也会通过左外连接获取其关联的对象.
    //可以通过 @OneToOne 的 fetch 属性来修改加载策略. 但依然会再发送 SQL 语句来初始化其关联的对象
    //这说明在不维护关联关系的一方, 不建议修改 fetch 属性.
    @Test
    public void testOneToOneFind2(){
        Manager mgr = entityManager.find(Manager.class, 1);
        System.out.println(mgr.getName());

        System.out.println(mgr.getDepartment().getClass().getName());
    }

    //1.默认情况下, 若获取维护关联关系的一方, 则会通过左外连接获取其关联的对象.
    //但可以通过 @OntToOne 的 fetch 属性来修改加载策略.
    @Test
    public void testOneToOneFind(){
        Department dept = entityManager.find(Department.class, 1);
        System.out.println(dept.getDeptName());
        System.out.println(dept.getManager().getClass().getName());
    }
}    

映射双向多对多的关联关系(由一方放弃主键维护)

Item

@Table(name = "items")
@Entity
public class Item {

    @Id
    @GeneratedValue
    private Integer id;

    @Column(name = "item_name")
    private String itemName;


    /**
     * 使用@JoinTable来映射中间表:
     *      @JoinTable(name="中间表名称",
     *                 joinColumns=@joinColumn(name="本类的外键",
     *                                         referencedColumnName="本类与外键对应的主键"),
     *                 inversejoinColumns=@JoinColumn(name="对方类的外键",
     *                                         referencedColunName="对方类与外键对应的主键")
     *                 )
     *
     */
    @ManyToMany
    @JoinTable(name = "item_category",
            joinColumns = @JoinColumn(name = "item_id", referencedColumnName = "id"),
            inverseJoinColumns = @JoinColumn(name = "category_id", referencedColumnName = "id")
    )
    private Set<Category> categories = new HashSet<>();

Category

@Table(name = "category")
@Entity
public class Category {

    @Id
    @GeneratedValue
    private Integer id;

    @Column(name = "category_name")
    private String categoryName;

    @ManyToMany(mappedBy = "categories")
    private Set<Item> items = new HashSet<>();
}    

测试(跟hibernate一样)

    //多对所的保存
    @Test
    public void testManyToManyPersist(){
        Item i1 = new Item();
        i1.setItemName("i-1");

        Item i2 = new Item();
        i2.setItemName("i-2");

        Category c1 = new Category();
        c1.setCategoryName("C-1");

        Category c2 = new Category();
        c2.setCategoryName("C-2");

        //设置关联关系
        i1.getCategories().add(c1);
        i1.getCategories().add(c2);

        i2.getCategories().add(c1);
        i2.getCategories().add(c2);

        c1.getItems().add(i1);
        c1.getItems().add(i2);

        c2.getItems().add(i1);
        c2.getItems().add(i2);

        //执行保存
        entityManager.persist(i1);
        entityManager.persist(i2);
        entityManager.persist(c1);
        entityManager.persist(c2);
    }


    //对于关联的集合对象, 默认使用懒加载的策略.
    //使用维护关联关系的一方获取, 还是使用不维护关联关系的一方获取, SQL 语句相同. 
    @Test
    public void testManyToManyFind(){
//      Item item = entityManager.find(Item.class, 5);
//      System.out.println(item.getItemName());
//      
//      System.out.println(item.getCategories().size());

        Category category = entityManager.find(Category.class, 3);
        System.out.println(category.getCategoryName());
        System.out.println(category.getItems().size());
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
hibernate-jpa-2.1-api 1.0.2是一个Java持久化规范的实现库。它是基于JPA(Java Persistence API)2.1规范的Hibernate实现。Hibernate是一个流行的ORM(对象关系映射)框架,用于在Java应用程序和关系数据库之间进行数据持久化。 该版本的hibernate-jpa-2.1-api是对JPA 2.1规范的实现,并且是Hibernate团队为了确保应用程序与Java EE 7兼容性而发布的一个版本。 JPA是一种使用对象模型操作数据库的标准规范,它提供了一组API,使开发人员可以使用面向对象的方式访问和操作数据库。Hibernate作为一个JPA的实现,提供了许多附加的功能和特性,使得开发人员可以更加简化和灵活地进行数据库操作。 通过使用hibernate-jpa-2.1-api,开发人员可以使用JPA的标准API,以及Hibernate提供的独有特性,来实现应用程序的数据持久化需求。它提供了实体管理器,用于管理实体对象的生命周期,以及CRUD操作。此外,它还提供了用于查询和各种持久化注解的支持。 通常情况下,使用hibernate-jpa-2.1-api需要将其添加到项目的依赖中,并与其他必需的Hibernate库一起使用。开发人员需要熟悉JPA的基本概念和API,并且理解Hibernate特有的扩展和配置选项。 总的来说,hibernate-jpa-2.1-api 1.0.2提供了开发人员在使用JPA进行数据持久化时的基本工具和功能。它是Hibernate团队为了支持JPA 2.1规范而发布的一个版本,开发人员可以使用它来简化和灵活地操作数据库。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值