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


           实体Customer:用户。

      实体Order:订单。

      Customer和Order是一对多关系。那么在JPA中,如何表示一对多的双向关联呢?

      JPA使用@OneToMany和@ManyToOne来标识一对多的双向关联。一的一端(Customer)使用@OneToMany,多端(Order)使用@ManyToOne。

      在JPA规范中,一对多的双向关系由多端(Order)来维护。就是说多端(Order)为关系维护端,负责关系的增删改查。一端(Customer)则为关系被维护端,不能维护关系。

      一端(Customer)@OneToMany注释的mappedBy="customer"属性表明Customer是关系被维护端。

      多端(Order)使用@ManyToOne和@JoinColumn来注释属性CUSTOMER_ID,@ManyToOne表明Order是多端,@JoinColumn设置在Order表中的关联字段(外键)。

         Customer实体类如下:

    /**
     *数据库持久化类
     * @author z
     *
     */
    @Table(name="JPA_CUSTOMERS")//主要是映射表名对应的数据库表名JPA_CUSTOMER默认情况下可以不写表名与持久化类名相同
    @Entity //表明这是一个持久化类
    public class Customer {
        
        private Integer id;
        private String lastName;
        private String email;
        private int  age ;
        
        private Date createdTime;
        private Date birth;
        
        /**
         * 单向一对多关系映射
         * 1、添加多的一方的集合属性
         */
          private Set<Order> orders=new HashSet<>();
        
        /**
         * 定义各数据列必须加在get方法上
         * @return
         */
        //定义主键,生成主键的策略AUTO自动的根据数据的类型生成主键
        @GeneratedValue(strategy=GenerationType.AUTO)
        @Id //定义数据列
    //    @Column(name="ID")//定义数据库的列名如果与字段名一样可以省略
        
        //使用table生成主键
    //    @TableGenerator(name="ID_GENERATOR",
    //            table="JPA_ID_GENERATORS",
    //            pkColumnName="PK_NAME",
    //            pkColumnValue="CUSTOMER_ID",
    //            valueColumnName="PK_VALUE",
    //            allocationSize=100
    //            
    //            
    //            )
    //    
    //    @GeneratedValue(strategy=GenerationType.TABLE,generator="ID_GENERATOR")
    //    @Id
        public Integer getId() {
            return id;
        }
        public void setId(Integer id) {
            this.id = id;
        }
        
        @Column(name="LAST_NAME",length=50,nullable=false) //nullable false表示此字段不能为空
        public String getLastName() {
            return lastName;
        }
        public void setLastName(String lastName) {
            this.lastName = lastName;
        }
        public String getEmail() {
            return email;
        }
        public void setEmail(String email) {
            this.email = email;
        }
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
            this.age = age;
        }
        
        @Temporal(TemporalType.TIMESTAMP)
        public Date getCreatedTime() {
            return createdTime;
        }
        public void setCreatedTime(Date createdTime) {
            this.createdTime = createdTime;
        }
        @Temporal(TemporalType.DATE)
        public Date getBirth() {
            return birth;
        }
        public void setBirth(Date birth) {
            this.birth = birth;
        }
        
        //映射单向一对多的关联关系
        //使用@OneToMany 来映射一对多的关联关系
        //使用@JoinColumn 来映射外键列的名称
        //可以使用@OneToMany的fetch 属性来修改默认的加载策略
        //可以通过@OneToMany的cascade 属性来修改默认的删除策略
        //cascade={CascadeType.REMOVE} 会把主表和从表的数据都删除
        //mappedBy表明放弃关联关系维护并且不能在使用
        //注意:若在一的一端@oneToMany 中使用mapperBy属性,则@oneToMany端就不能在使用@JoinColumn(name="CUSTOMER_ID")属性
    //    @JoinColumn(name="CUSTOMER_ID")
        @OneToMany(fetch=FetchType.EAGER,cascade={CascadeType.REMOVE},mappedBy="customer")
       public Set<Order> getOrders() { 
            return orders;
        }
        public void setOrders(Set<Order> orders) {
            this.orders = orders;
        }
        
        //工具方法,不需要映射为数据表的一列
        @Transient
        public String getInfo(){
            return "lastName:"+lastName+",email:"+email;
        }
        @Override
        public String toString() {
            return "Customer [id=" + id + ", lastName=" + lastName + ", email=" + email + ", age=" + age + ", createdTime="
                    + createdTime + ", birth=" + birth + "]";
        }
        
    
    }
    
    
    
     

    多的一端实体类Order如下:

    /**
     * 单向多对一
     * 一个订单可以有多个用户
     * 一个用户可以有多个订单
     * @author z
     *
     */
    @Table(name="JPA_ORDERS")
    @Entity
    public class Order {
        private Integer id;
        private String orderName;
        
        private Customer customer;
        @GeneratedValue//使用默认的主键生成方式
        @Id
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
        @Column(name="ORDER_NAME")
        public String getOrderName() {
            return orderName;
        }
    
        public void setOrderName(String orderName) {
            this.orderName = orderName;
        }
        //映射单向n-1的关联关系
        //使用@ManyToOne 来映射多对一的关系
        //使用@JoinColumn 来映射外键
        //可以使用@ManyToOne的fetch属性来修改默认的关联属性的加载策略
        @JoinColumn(name="CUSTOMER_ID")//外键列的列名
        @ManyToOne(fetch=FetchType.LAZY)
        public Customer getCustomer() {
        return customer;
        }
    
        public void setCustomer(Customer customer) {
            this.customer = customer;
        }
    
        @Override
        public String toString() {
            return "Order [id=" + id + ", orderName=" + orderName + ", customer=" + customer+ "]";
        }
        
    
    }

    简单的测试类

    public class JPATest {
        private EntityManagerFactory entityManagerFactory;
        private EntityManager entityManager;
        private EntityTransaction transaction;
        @Before
        public void init(){
            entityManagerFactory= Persistence.createEntityManagerFactory("jpa-1");
            entityManager=entityManagerFactory.createEntityManager();
            transaction=entityManager.getTransaction();
            transaction.begin();//开启事务
            
        }
        @After
        public void destroy(){
            transaction.commit();
            entityManager.close();
            entityManagerFactory.close();
        }
        
        //修改
        @Test
        public void testUpdate(){
            Customer customer=entityManager.find(Customer.class, 4);
            customer.getOrders().iterator().next().setOrderName("O-XXX-10");
            
        }
        
         //删除
        //默认情况下,若删除1的一端,则会先把关联的多的一段的外键置空,然后删除一的一端
        ////可以通过@OneToMany的cascade 属性来修改默认的删除策略
        @Test
        public void testOneToManyRemove(){
            Customer customer=entityManager.find(Customer.class, 7);
            entityManager.remove(customer);
            
        }
        
        //默认对关联多的一方使用懒加载的加载策略(延迟加载)
        //可以使用@OneToMany的fetch 属性来修改默认的加载策略
        //查询
        @Test
        public void testOneToManyFind(){
            Customer customer=entityManager.find(Customer.class,6);
            System.out.println(customer.getLastName());
            
            System.out.println(customer.getOrders().size());
            
        }
        
        //双向一对多的关联关系在执行保存时
        //若先保存多的一端,在保存一的一端,默认情况下,会多出四条update语句
        //若先保存一的一端则会多出2(n)条update语句
        //在进行双向一对多的关联关系时,建议使用多的一方来维护关联关系,而1的一方不维护关联关系,这样会有效的减少sql语句
        //注意:若在一的一端@oneToMany 中使用mapperBy属性,则@oneToMany端就不能在使用@JoinColumn(name="CUSTOMER_ID")属性//保存
        @Test
        public void testOneToManyPersist(){
            Customer customer=new Customer();
            customer.setAge(16);
            customer.setBirth(new Date());
            customer.setCreatedTime(new Date());
            customer.setEmail("CC@163.com");
            customer.setLastName("AA");
            
            Order order1=new Order();
            order1.setOrderName("o-CC-1");
            
            Order order2=new Order();
            order2.setOrderName("o-CC-2");
            
            //建立关联关系
            customer.getOrders().add(order1);
            customer.getOrders().add(order2);
            //执行保存操作
            entityManager.persist(customer);
            entityManager.persist(order1);
            entityManager.persist(order2);    
            
        }
        }

    源码地址:https://github.com/wuhongpu/JPA.git

  • 相关阅读:
    方向ajax(http long request实现实时通信)
    HTTP防盗链与反防盗链
    linux开启过程详解
    自动化运维工具----saltstack安装及配置
    python----网络编程(TCP通讯)
    windows----bat方式实现ftp推送
    shell----ftp推送
    python----FTP文件拉取(new)
    haproxy----四层负载均衡
    python----时间转换
  • 原文地址:https://www.cnblogs.com/a8457013/p/7770939.html
Copyright © 2020-2023  润新知