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

新建项目项目请参考《JPA(二):HellWord工程》,基于上一章讲解的《JPA(五):映射关联关系------映射单向多对一的关联关系》中的例子进行修改(需要清空数据中的表,因为本例子还是使用customer,order表来测试,但是关联关系发生了变化):

Customer.java

package com.dx.jpa.singlemanytoone;

import java.util.Date;
import java.util.HashSet;
import java.util.Set; import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
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;
private Set<Order> orders = new HashSet<>(); @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;
} // 映射一对多的关联关系
// @JoinColumn 用来映射一对多的关联关系
// @OneToMany 用来映射外键列
@JoinColumn(name = "CUSTOMER_ID")
@OneToMany()
public Set<Order> getOrders() {
return orders;
} public void setOrders(Set<Order> orders) {
this.orders = orders;
} // 帮助方法,不希望保存到数据库,但是需要动态获取Customer对象的属性。
@Transient
public String getCustomerInfo() {
return "username:" + fullName + ",age:" + age;
}
}

注意:这里在Customer.java中添加了一对多的注解@OneToMany:

    // 映射一对多的关联关系
// @JoinColumn 用来映射一对多的关联关系
// @OneToMany 用来映射外键列
@JoinColumn(name = "CUSTOMER_ID")
@OneToMany()
public Set<Order> getOrders() {
return orders;
}

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.Table; @Entity
@Table(name = "jpa_order")
public class Order {
private Integer id;
private String name; @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;
}
}

初始化JPA项目时,创建表语句如下:

Hibernate: 

    create table hibernate_sequence (
next_val bigint
) engine=InnoDB
Hibernate: insert into hibernate_sequence values ( 1 )
Hibernate: insert into hibernate_sequence values ( 1 )
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)

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.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>

此时在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"); Order order2 = new Order();
order2.setName("O-AA-02"); customer.getOrders().add(order1);
customer.getOrders().add(order2); entityManager.persist(customer);
entityManager.persist(order1);
entityManager.persist(order2);
}

此时执行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_customer
(age, birth, createDate, FULL_NAME, id)
values
(?, ?, ?, ?, ?)
Hibernate:
insert
into
jpa_order
(name, id)
values
(?, ?)
Hibernate:
insert
into
jpa_order
(name, id)
values
(?, ?)
Hibernate:
update
jpa_order
set
CUSTOMER_ID=?
where
id=?
Hibernate:
update
jpa_order
set
CUSTOMER_ID=?
where
id=?

此时并不是因为customer,order保存顺序导致的(即使调换添加先后顺序也会多处update语句),因为多的一端在插入时不会插入外键列,因此一定会多处update语句。

查询测试

添加测试函数:

    @Test
public void testFind() {
Customer customer = entityManager.find(Customer.class, 1);
System.out.println(customer.getFullName());
System.out.println(customer.getOrders().size());
}

执行打印结果:

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=?
AA
Hibernate:
select
orders0_.CUSTOMER_ID as CUSTOMER3_1_0_,
orders0_.id as id1_1_0_,
orders0_.id as id1_1_1_,
orders0_.name as name2_1_1_
from
jpa_order orders0_
where
orders0_.CUSTOMER_ID=?
2

从打印结果上可以看出默认采用懒加载的方式,修改Customer.java中的@OneToMany()中的fetch属性为:@OneToMany(fetch=FetchType.EAGER),此时才会出现非懒加载:

此时,再次执行插叙测试函数,执行打印结果如下:

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_,
orders1_.CUSTOMER_ID as CUSTOMER3_1_1_,
orders1_.id as id1_1_1_,
orders1_.id as id1_1_2_,
orders1_.name as name2_1_2_
from
jpa_customer customer0_
left outer join
jpa_order orders1_
on customer0_.id=orders1_.CUSTOMER_ID
where
customer0_.id=?
AA
2

修改测试

修改测试函数:

    @Test
public void testUpdate() {
Customer customer = entityManager.find(Customer.class, 1);
customer.getOrders().iterator().next().setName("O-XX-01");
}

此时执行打印结果为:

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_,
orders1_.CUSTOMER_ID as CUSTOMER3_1_1_,
orders1_.id as id1_1_1_,
orders1_.id as id1_1_2_,
orders1_.name as name2_1_2_
from
jpa_customer customer0_
left outer join
jpa_order orders1_
on customer0_.id=orders1_.CUSTOMER_ID
where
customer0_.id=?
Hibernate:
update
jpa_order
set
name=?
where

注意:这时@OneToMany(fetch=FetchType.EAGER)

删除测试

删除测试函数:

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

此时customer表内容记录如下:

order表记录如下:

此时执行删除,可以删除成功,删除后customer.id=4的记录被删除了,而order表中id=5,6记录的customer_id值被置为null。

删除后结果为:

customer表记录:

order表记录:

从执行打印语句可以看出:

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_,
orders1_.CUSTOMER_ID as CUSTOMER3_1_1_,
orders1_.id as id1_1_1_,
orders1_.id as id1_1_2_,
orders1_.name as name2_1_2_
from
jpa_customer customer0_
left outer join
jpa_order orders1_
on customer0_.id=orders1_.CUSTOMER_ID
where
customer0_.id=?
Hibernate:
update
jpa_order
set
CUSTOMER_ID=null
where
CUSTOMER_ID=?
Hibernate:
delete
from
jpa_customer
where
id=?

实际上,我们可以通过配置@OneToMany的级联删除属性,可以通过删除customer来实现级联删除的。

修改Customer.java中的@OneToMany注解信息:

这里修改配置后Customer的getOrders()方法的注解为:

    // 映射一对多的关联关系
// @JoinColumn 用来映射一对多的关联关系
// @OneToMany 用来映射外键列
@JoinColumn(name = "CUSTOMER_ID")
@OneToMany(fetch=FetchType.EAGER,cascade=CascadeType.REMOVE)
public Set<Order> getOrders() {
return orders;
}

此时,测试通过删除customer.id=1的记录,测试结果可以成功级联删除,执行打印结果为:

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_,
orders1_.CUSTOMER_ID as CUSTOMER3_1_1_,
orders1_.id as id1_1_1_,
orders1_.id as id1_1_2_,
orders1_.name as name2_1_2_
from
jpa_customer customer0_
left outer join
jpa_order orders1_
on customer0_.id=orders1_.CUSTOMER_ID
where
customer0_.id=?
Hibernate:
update
jpa_order
set
CUSTOMER_ID=null
where
CUSTOMER_ID=?
Hibernate:
delete
from
jpa_order
where
id=?
Hibernate:
delete
from
jpa_order
where
id=?
Hibernate:
delete
from
jpa_customer
where
id=?

JPA(六):映射关联关系------映射单向一对多的关联关系的更多相关文章

  1. 7、单向一对多的关联关系(1的一方有n的一方的集合属性,n的一方却没有1的一方的引用)

    单向一对多的关联关系 具体体现:1的一方有n的一方的集合的引用,n的一方却没有1的一方的引用 举个例子:顾客Customer对订单Order是一个单向一对多的关联关系.Customer一方有对Orde ...

  2. JPA中实现单向一对多的关联关系

    场景 JPA入门简介与搭建HelloWorld(附代码下载): https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/103473937 ...

  3. Hibernate5.2关联关系之单向一对多(一)

    Hibernate5.2之单向一对多 一. 简介    Hibernate中最复杂的应该就是各种关联(单向一对多.单向多对一.双向一对多.一对一.多对多)关系的映射,于是笔者就想着去写一些关于Hibe ...

  4. JPA 单向一对多关联关系

    映射单向一对多的关联关系 1.首先在一的一端加入多的一端的实体类集合 2.使用@OneToMany 来映射一对多的关联关系3.使用@JoinColumn 来映射外键列的名称4.可以使用@OneToMa ...

  5. JPA中实现双向一对多的关联关系

    场景 JPA入门简介与搭建HelloWorld(附代码下载): https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/103473937 ...

  6. JPA(五):映射关联关系------映射单向多对一的关联关系

    映射单向多对一的关联关系 新建Customer.java: package com.dx.jpa.singlemanytoone; import java.util.Date; import java ...

  7. jpa单向一对多关联映射

    如果在一的@OneToMany有@manyToOne则是双向一对多关联,如果在多的那面没有@manyToOne关联则是单向一对多关联 class和student是一对多的关系 表结构 student ...

  8. JPA总结——实体关系映射(一对多@OneToMany)

    JPA总结——实体关系映射(一对多@OneToMany) 注意:本文出自“阿飞”的博客,如果要转载本文章,请与作者联系! 并注明来源: http://blog.sina.com.cn/s/blog_4 ...

  9. JPA 对象关系映射之关联关系映射策略

    关联关系映射 关联关系映射,是映射关系中比较复杂的一种映射关系,总的说来有一对一.一对多和多对多几种关系.细分起来他们又有单向和双向之分.下面我们逐一介绍一下. 回页首 单向 OneToOne 单向一 ...

随机推荐

  1. Activator 动态构造对象

    Activator  意义: 用于动态构造对象 语法1: 根据指定的泛型类型构造对象 Activator.CreateInstance<类型>() 语法2: 根据程序集和类型名构造对象 S ...

  2. 【Hadoop】HDFS - 创建文件流程详解

    1.本文目的 通过解析客户端创建文件流程,认知hadoop的HDFS系统的一些功能和概念. 2.主要概念 2.1 NameNode(NN): HDFS系统核心组件,负责分布式文件系统的名字空间管理.I ...

  3. 在Win7中用ftp的方法

    我的电脑是Win7  32位操作系统,之前一直没有成功使用过ftp 之初以为是ftp客户端的问题,换了几个软件都不行,然后换我的一台vps服务器(win2003)连接同一个ftp服务器可以正常连接使用 ...

  4. Ubuntu 中启用 root 帐号

    参考:http://linuxtoy.org/archives/howto_enable_ubuntu_root_account.html 如果你实在需要在 Ubuntu 中启用 root 帐号的话, ...

  5. Unity3D实践系列11, 组件的添加和访问

    当把一个脚本附加到一个GameObject上的时候,这个GameObject就有了脚本组件. 通过GameObject的属性获取组件 比如如下: [RequireComponent(typeof(Ri ...

  6. url提交参数类

    url提交参数类 type /// <summary> /// 准备url /// </summary> TynUrl = class private FUrl, FComma ...

  7. Android实现对HOME键的捕获和屏蔽

    1.1. 在AndroidManifest.xml中加上权限,禁止HOME键. <uses-permission android:name="android.permission.DI ...

  8. go1.8之安装配置具体步骤

    操作系统: CentOS 6.9_x64 go语言版本: 1.8.3 安装go 这里直接安装二进制,其它方式请自行搜索. 1.下载并安装go 命令如下: ? 1 2 3 wget https://st ...

  9. Android之Activity与fragment完整生命周期图

    转自:https://github.com/xxv/android-lifecycle

  10. Android性能优化工具之Systrace

    本文大部分内容来自:http://www.androidperformance.com/android-performance-tools-systrace-1.html?utm_source=tui ...