概述
在领域模型中, 类与类之间最普遍的关系就是关联关系.
在 UML 中, 关联是有方向的。
以 Customer 和 Order 为例: 一个用户能发出多个订单, 而一个订单只能属于一个客户。从 Order 到 Customer 的关联是多对一关联; 而从 Customer 到 Order 是一对多关联。
【1】Customer与Order
关联关系映射为Order:Customer=N:1,Order中有Customer属性,Customer中没有Order属性。
映射单向 n-1的关联关系核心:
- 使用@ManyToOne来映射多对一的关联关系
- 使用@JoinColumn 来映射外键
- 使用 @ManyToOne 的fetch 属性来修改默认的关联属性的加载策略
Order如下:
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
@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)
@ManyToOne(fetch=FetchType.EAGER)
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
}
Customer如下:
单向多对一中,一的一端(Customer)并不需要保持多的一端(Order)。
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Cacheable;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;
@NamedQuery(name="testNamedQuery", query="FROM Customer c WHERE c.id = ?")
@Cacheable(true)
@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;
public Customer() {
}
public Customer(String lastName, int age) {
super();
this.lastName = lastName;
this.age = age;
}
// @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")
@GeneratedValue(strategy=GenerationType.AUTO)
@Id
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
@Column(name="LAST_NAME",length=50,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;
}
@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 + "]";
}
}
【2】多对一的持久化操作
保存多对一时,建议先保存1的一端,后保存n的一端,这样不会多出额外的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);
}
控制台输出如下:
Hibernate:
insert
into
JPA_CUTOMERS
(age, birth, createdTime, email, LAST_NAME)
values
(?, ?, ?, ?, ?)
Hibernate:
insert
into
JPA_ORDERS
(CUSTOMER_ID, ORDER_NAME)
values
(?, ?)
Hibernate:
insert
into
JPA_ORDERS
(CUSTOMER_ID, ORDER_NAME)
values
(?, ?)
即,连续三条插入语句。
如果先保存Order呢?将会多出Update语句
如下所示:
//ִ执行保存操作
entityManager.persist(order1);
entityManager.persist(order2);
entityManager.persist(customer);
控制台输出如下:
Hibernate:
insert
into
JPA_ORDERS
(CUSTOMER_ID, ORDER_NAME)
values
(?, ?)
Hibernate:
insert
into
JPA_ORDERS
(CUSTOMER_ID, ORDER_NAME)
values
(?, ?)
Hibernate:
insert
into
JPA_CUTOMERS
(age, birth, createdTime, email, LAST_NAME)
values
(?, ?, ?, ?, ?)
Hibernate:
update
JPA_ORDERS
set
CUSTOMER_ID=?,
ORDER_NAME=?
where
id=?
Hibernate:
update
JPA_ORDERS
set
CUSTOMER_ID=?,
ORDER_NAME=?
where
id=?
总结如下:
保存多对一时,建议先保存1的一端,后保存n的一端,这样不会多出额外的update语句。
【3】多对一的获取操作
默认情况下,使用左外连接的方式来获取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());
}
此时Order实体类中fetch为eager(默认值):
@JoinColumn(name="CUSTOMER_ID")
@ManyToOne(fetch=FetchType.EAGER)
public Customer getCustomer() {
return customer;
}
即,默认使用左外连接方式来获取n的一端的对象和其关联的1的一端的对象。
如果将feteh属性改为lazy:
@JoinColumn(name="CUSTOMER_ID")
@ManyToOne(fetch=FetchType.LAZEY)
public Customer getCustomer() {
return customer;
}
其控制台输出如下:
【4】多对一的删除操作
① 可以任意删除n的一端,但是不能随意删除1的一端,因为有外键约束。
示例如下:
//不能直接删除1的一端,因为有外键约束
@Test
public void testManyToOneRemove(){
Order order = entityManager.find(Order.class, 6);
entityManager.remove(order);
}
② 如果删除1的一端将会抛出异常:
//不能直接删除1的一端,因为有外键约束
@Test
public void testManyToOneRemove(){
Customer customer = entityManager.find(Customer.class, 4);
entityManager.remove(customer);
}
③ 如果外键约束不存在,则可以删除1的一端:
④ 删除一个不存在的实体,同样会抛出异常:
【5】多对一的更新操作
示例如下:
@Test
public void testManyToOneUpdate(){
Order order = entityManager.find(Order.class, 2);
order.getCustomer().setLastName("FFF");
}
控制台输出如下:
Hibernate:
select
order0_.id as id1_1_1_,
order0_.CUSTOMER_ID as CUSTOMER3_1_1_,
order0_.ORDER_NAME as ORDER_NA2_1_1_,
customer1_.id as id1_0_0_,
customer1_.age as age2_0_0_,
customer1_.birth as birth3_0_0_,
customer1_.createdTime as createdT4_0_0_,
customer1_.email as email5_0_0_,
customer1_.LAST_NAME as LAST_NAM6_0_0_
from
JPA_ORDERS order0_
left outer join
JPA_CUTOMERS customer1_
on order0_.CUSTOMER_ID=customer1_.id
where
order0_.id=?
Hibernate:
update
JPA_CUTOMERS
set
age=?,
birth=?,
createdTime=?,
email=?,
LAST_NAME=?
where
id=?
最后
以上就是欣慰电脑为你收集整理的JPA - 单向多对一映射的全部内容,希望文章能够帮你解决JPA - 单向多对一映射所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复