JPA:映射关联关系------映射单向多对一的关联关系

Posted yy3b2007com

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JPA:映射关联关系------映射单向多对一的关联关系相关的知识,希望对你有一定的参考价值。

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

新建Customer.java:

技术分享图片
package com.dx.jpa.singlemanytoone;

import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;

@Entity
@Table(name = "jpa_customer")
public class Customer {
    private Integer id;
    private String fullName;
    private Integer age;
    private Date birth;
    private Date createDate;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    @Column(name = "FULL_NAME", length = 64, nullable = false)
    public String getFullName() {
        return fullName;
    }

    public void setFullName(String fullName) {
        this.fullName = fullName;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Temporal(TemporalType.DATE)
    public Date getBirth() {
        return birth;
    }

    public void setBirth(Date birth) {
        this.birth = birth;
    }

    @Temporal(TemporalType.TIMESTAMP)
    public Date getCreateDate() {
        return createDate;
    }

    public void setCreateDate(Date createDate) {
        this.createDate = createDate;
    }

    // 帮助方法,不希望保存到数据库,但是需要动态获取Customer对象的属性。
    @Transient
    public String getCustomerInfo() {
        return "username:" + fullName + ",age:" + age;
    }
}
View Code

Order.java:

package com.dx.jpa.singlemanytoone;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

@Entity
@Table(name = "jpa_order")
public class Order {
    private Integer id;
    private String name;
    private Customer customer;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    // @JoinColumn来映射外键
    // @ManyToOne映射单项一对多映射关系
    @JoinColumn(name = "CUSTOMER_ID")
    @ManyToOne()
    public Customer getCustomer() {
        return customer;
    }

    public void setCustomer(Customer customer) {
        this.customer = customer;
    }

}

Client.java测试类:

技术分享图片
package com.dx.jpa.singlemanytoone;

import java.util.Date;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;

import org.hamcrest.CustomTypeSafeMatcher;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class Client {
    private String persistenceUnitName = "Jpa-helloword";
    private EntityManagerFactory entityManagerFactory = null;
    private EntityManager entityManager = null;
    private EntityTransaction entityTransaction = null;

    @Before
    public void init() {
        // 1.创建EntityManagerFactory
        entityManagerFactory = Persistence.createEntityManagerFactory(persistenceUnitName);
        // 2.创建EntityManager
        entityManager = entityManagerFactory.createEntityManager();
        // 3.开始事务
        entityTransaction = entityManager.getTransaction();
        entityTransaction.begin();
    }

    @After
    public void destory() {
        // 5.提交事务
        entityTransaction.commit();

        // 6.关闭EntityManager
        entityManager.close();
        // 7.关闭EnityManagerFactory
        entityManagerFactory.close();
    }
}
View Code

将Customer,Person添加到jpa配置文件persistence.xml中:

技术分享图片
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0"
    xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
    <persistence-unit name="Jpa-helloword"
        transaction-type="RESOURCE_LOCAL">
        <!-- 配置使用什么 ORM 产品来作为 JPA 的实现 -->
        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
        <!-- 添加持久化类 -->
        <class>com.dxsoft.jpa.helloword.Person</class>
        <class>com.dx.jpa.singlemanytoone.Customer</class>
        <class>com.dx.jpa.singlemanytoone.Order</class>
        <properties>
            <!-- 数据库的相关配置 -->
            <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
            <property name="javax.persistence.jdbc.url" value="jdbc:mysql://127.0.0.1:3306/jpa" />
            <property name="javax.persistence.jdbc.user" value="root" />
            <property name="javax.persistence.jdbc.password" value="root" />
            <!-- 指定方言 
            MySQL                org.hibernate.dialect.MySQLDialect
            MySQL with InnoDB    org.hibernate.dialect.MySQLInnoDBDialect
            MySQL with MyISAM    org.hibernate.dialect.MySQLMyISAMDialect
            MySQL5                org.hibernate.dialect.MySQL5Dialect
            MySQL5 with InnoDB    org.hibernate.dialect.MySQL5InnoDBDialect
            -->
            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect" />
            <property name="hibernate.show_sql" value="true" />
            <property name="hibernate.format_sql" value="true" />
            <!-- 
            create:每次加载hibernate时都会删除上一次的生成的表,然后根据你的model类再重新来生成新表,哪怕两次没有任何改变也要这样执行,这就是导致数据库表数据丢失的一个重要原因。<br>
            create-drop :每次加载hibernate时根据model类生成表,但是sessionFactory一关闭,表就自动删除。<br>
            update:最常用的属性,第一次加载hibernate时根据model类会自动建立起表的结构(前提是先建立好数据库),以后加载hibernate时根据 model类自动更新表结构,即使表结构改变了但表中的行仍然存在不会删除以前的行。要注意的是当部署到服务器后,表结构是不会被马上建立起来的,是要等 应用第一次运行起来后才会。<br>
            validate :每次加载hibernate时,验证创建数据库表结构,只会和数据库中的表进行比较,不会创建新表,但是会插入新值。 <br> 
            -->
            <property name="hibernate.hbm2ddl.auto" value="update" />            
        </properties>
    </persistence-unit>
</persistence>
View Code

执行初始化时,创建表打印语句如下:

Hibernate: 
    
    create table jpa_customer (
       id integer not null,
        age integer,
        birth date,
        createDate datetime,
        FULL_NAME varchar(64) not null,
        primary key (id)
    ) engine=InnoDB
Hibernate: 
    
    create table jpa_order (
       id integer not null,
        name varchar(255),
        CUSTOMER_ID integer,
        primary key (id)
    ) engine=InnoDB
Hibernate: 
    
    alter table jpa_order 
       add constraint FK7glkngwj74nr8h2amofkp1fjd 
       foreign key (CUSTOMER_ID) 
       references jpa_customer (id)

此时查看表,发现jpa_order表上新建了外键:

技术分享图片

测试添加:

添加测试函数:

    @Test
    public void testPersist() {
        Customer customer = new Customer();
        customer.setFullName("AA");
        customer.setAge(26);
        customer.setBirth(new Date());
        customer.setCreateDate(new Date());

        Order order1 = new Order();
        order1.setName("O-AA-01");
        order1.setCustomer(customer);

        Order order2 = new Order();
        order2.setName("O-AA-02");
        order2.setCustomer(customer);

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

此时打印语句为:

技术分享图片
Hibernate: 
    select
        next_val as id_val 
    from
        hibernate_sequence for update
            
Hibernate: 
    update
        hibernate_sequence 
    set
        next_val= ? 
    where
        next_val=?
Hibernate: 
    select
        next_val as id_val 
    from
        hibernate_sequence for update
            
Hibernate: 
    update
        hibernate_sequence 
    set
        next_val= ? 
    where
        next_val=?
Hibernate: 
    select
        next_val as id_val 
    from
        hibernate_sequence for update
            
Hibernate: 
    update
        hibernate_sequence 
    set
        next_val= ? 
    where
        next_val=?
Hibernate: 
    insert 
    into
        jpa_customer
        (age, birth, createDate, FULL_NAME, id) 
    values
        (?, ?, ?, ?, ?)
Hibernate: 
    insert 
    into
        jpa_order
        (CUSTOMER_ID, name, id) 
    values
        (?, ?, ?)
Hibernate: 
    insert 
    into
        jpa_order
        (CUSTOMER_ID, name, id) 
    values
        (?, ?, ?)
View Code

修改customer,order1,order2添加顺序:

    @Test
    public void testPersist() {
        Customer customer = new Customer();
        customer.setFullName("BB");
        customer.setAge(26);
        customer.setBirth(new Date());
        customer.setCreateDate(new Date());

        Order order1 = new Order();
        order1.setName("O-BB-01");
        order1.setCustomer(customer);

        Order order2 = new Order();
        order2.setName("O-BB-02");
        order2.setCustomer(customer);

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

执行打印sql语句如下:

技术分享图片
Hibernate: 
    select
        next_val as id_val 
    from
        hibernate_sequence for update
            
Hibernate: 
    update
        hibernate_sequence 
    set
        next_val= ? 
    where
        next_val=?
Hibernate: 
    select
        next_val as id_val 
    from
        hibernate_sequence for update
            
Hibernate: 
    update
        hibernate_sequence 
    set
        next_val= ? 
    where
        next_val=?
Hibernate: 
    select
        next_val as id_val 
    from
        hibernate_sequence for update
            
Hibernate: 
    update
        hibernate_sequence 
    set
        next_val= ? 
    where
        next_val=?
Hibernate: 
    insert 
    into
        jpa_order
        (CUSTOMER_ID, name, id) 
    values
        (?, ?, ?)
Hibernate: 
    insert 
    into
        jpa_order
        (CUSTOMER_ID, name, id) 
    values
        (?, ?, ?)
Hibernate: 
    insert 
    into
        jpa_customer
        (age, birth, createDate, FULL_NAME, id) 
    values
        (?, ?, ?, ?, ?)
Hibernate: 
    update
        jpa_order 
    set
        CUSTOMER_ID=?,
        name=? 
    where
        id=?
Hibernate: 
    update
        jpa_order 
    set
        CUSTOMER_ID=?,
        name=? 
    where
        id=?
View Code

从打印信息中可以看出,此时是先插入的order,之后在修改其customer_id。比起之前的那种写法多出来了两次修改。

测试查询:

添加测试查询函数:

    @Test
    public void testSelect() {
        Order order = entityManager.find(Order.class, 3);
        System.out.println(order.getName());
        //System.out.println(order.getCustomer().getFullName());
    }

此时执行打印sql语句为:

Hibernate: 
    select
        order0_.id as id1_1_0_,
        order0_.CUSTOMER_ID as CUSTOMER3_1_0_,
        order0_.name as name2_1_0_,
        customer1_.id as id1_0_1_,
        customer1_.age as age2_0_1_,
        customer1_.birth as birth3_0_1_,
        customer1_.createDate as createDa4_0_1_,
        customer1_.FULL_NAME as FULL_NAM5_0_1_ 
    from
        jpa_order order0_ 
    left outer join
        jpa_customer customer1_ 
            on order0_.CUSTOMER_ID=customer1_.id 
    where
        order0_.id=?

从sql语句可以看出即使不插叙customer信息,也会使用left outer join把customer信息给关联出来。

修改Order的getCustomer方法的属性:

技术分享图片

修改Order属性为:

技术分享图片

重新测试查询:

    @Test
    public void testSelect() {
        Order order = entityManager.find(Order.class, 2);
        System.out.println("------------------------");
        System.out.println(order.getName());
        System.out.println("------------------------");
        System.out.println(order.getCustomer().getFullName());
        System.out.println("------------------------");
    }

打印sql语句为:

Hibernate: 
    select
        order0_.id as id1_1_0_,
        order0_.CUSTOMER_ID as CUSTOMER3_1_0_,
        order0_.name as name2_1_0_ 
    from
        jpa_order order0_ 
    where
        order0_.id=?
------------------------
O-BB-02
------------------------
Hibernate: 
    select
        customer0_.id as id1_0_0_,
        customer0_.age as age2_0_0_,
        customer0_.birth as birth3_0_0_,
        customer0_.createDate as createDa4_0_0_,
        customer0_.FULL_NAME as FULL_NAM5_0_0_ 
    from
        jpa_customer customer0_ 
    where
        customer0_.id=?
BB
------------------------

查询修改:

添加修改测试:

    @Test
    public void testUpdate() {
        Order order = entityManager.find(Order.class, 1);
        order.setName("O-BBB-01");
        order.getCustomer().setFullName("BBB");
    }

打印执行sql:

技术分享图片
Hibernate: 
    select
        order0_.id as id1_1_0_,
        order0_.CUSTOMER_ID as CUSTOMER3_1_0_,
        order0_.name as name2_1_0_ 
    from
        jpa_order order0_ 
    where
        order0_.id=?
Hibernate: 
    select
        customer0_.id as id1_0_0_,
        customer0_.age as age2_0_0_,
        customer0_.birth as birth3_0_0_,
        customer0_.createDate as createDa4_0_0_,
        customer0_.FULL_NAME as FULL_NAM5_0_0_ 
    from
        jpa_customer customer0_ 
    where
        customer0_.id=?
Hibernate: 
    update
        jpa_order 
    set
        CUSTOMER_ID=?,
        name=? 
    where
        id=?
Hibernate: 
    update
        jpa_customer 
    set
        age=?,
        birth=?,
        createDate=?,
        FULL_NAME=? 
    where
        id=?
View Code

查询删除:

测试删除多的一端:

    @Test
    public void testRemove() {
        Order order = entityManager.find(Order.class, 1);
        entityManager.remove(order);        
    }
    

执行打印语句:

Hibernate: 
    select
        order0_.id as id1_1_0_,
        order0_.CUSTOMER_ID as CUSTOMER3_1_0_,
        order0_.name as name2_1_0_ 
    from
        jpa_order order0_ 
    where
        order0_.id=?
Hibernate: 
    delete 
    from
        jpa_order 
    where
        id=?

删除一的一端,此时其在多的一端还对应的有数据记录:

技术分享图片

技术分享图片

执行测试函数:

    @Test
    public void testRemove() {
        Customer customer = entityManager.find(Customer.class, 3);
        entityManager.remove(customer);
    }

提示删除失败:

技术分享图片

再次修改,将多一端的对应的数据也删除后,再次尝试删除:

    @Test
    public void testRemove() {
        Order order = entityManager.find(Order.class, 2);
        entityManager.remove(order);

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

此时提示删除成功。 

以上是关于JPA:映射关联关系------映射单向多对一的关联关系的主要内容,如果未能解决你的问题,请参考以下文章

一口一口吃掉Hibernate——多对一单向关联映射

Hibernate框架学习之注解配置关系映射

7.0单向多对一的关联映射

JPA多对一单向关联

jpa多对一映射

Hibernate映射