码迷,mamicode.com
首页 > 其他好文 > 详细

6、JPA_映射单向多对一的关联关系(n的一方有1的引用,1的一方没有n的集合属性)

时间:2015-11-29 23:00:11      阅读:224      评论:0      收藏:0      [点我收藏+]

标签:

 

单向多对一的关联关系

具体体现:n的一方有1的引用,1的一方没有n的集合属性

举个例子:订单Order和顾客Customer是一个单向多对一的关联关系。Order是n的一方,有对Customer的引用;而Customer作为1的一方却没有Order的集合属性。

 

主要是对n的一方使用@ManyToOne和@JoinColumn注解。而1的一方不需要做任何修改。具体的映射方法

1、采用@ManyToOne注解映射多对一的关联关系,默认情况下采用“左外连接”的方式进行加载。可以通过配置@ManyToOne的fetch=FetchType.LAZY来设定加载策略为“懒加载”。

2、通过@JoinColumn注解来映射外键,其name属性用来指定外键列的列名。

 

在持久化多对一的时候有一个小的地方可以注意一下:先保存1的一方,后保存n的一方,这样可以少发送几条update SQL语句

 

下面列出清单:

List_1. Customer作为1的一方,没有Order的集合属性
技术分享
  1 package com.magicode.jpa.helloworld;
  2 
  3 import java.util.Date;
  4 
  5 import javax.persistence.Column;
  6 import javax.persistence.Entity;
  7 import javax.persistence.GeneratedValue;
  8 import javax.persistence.GenerationType;
  9 import javax.persistence.Id;
 10 import javax.persistence.Table;
 11 import javax.persistence.TableGenerator;
 12 //import javax.persistence.TableGenerator;
 13 import javax.persistence.Temporal;
 14 import javax.persistence.TemporalType;
 15 import javax.persistence.Transient;
 16 
 17 /**
 18  * @Entity 用于注明该类是一个实体类
 19  * @Table(name="t_customer") 表明该实体类映射到数据库的 t_customer 表
 20  */
 21 @Table(name="t_customer")
 22 @Entity
 23 public class Customer {
 24 
 25     private Integer id;
 26     private String lastName;
 27 
 28     private String email;
 29     private int age;
 30     
 31     private Date birthday;
 32     
 33     private Date createdTime;
 34 
 35     /**
 36      * @TableGenerator 标签的属性解释:
 37      * 
 38      *     ①、allocationSize 属性需要赋一个整数值。表示了bucket的容量。其默认值为50。
 39      *     ②、table 属性用于指定辅助表的表名。这里指定为t_id_generator数据表
 40      * 
 41      * 其基本思想就是:从table指定的辅助表中读取一个bucket段id号范围内的第一个数值,记为first_id。在后面持久化过程中的id号是从first_id开始依次递增1得到
 42      * 当递增到first_id + allocationSize 的时候,就会再一次从辅助表中读取一个first_id开始新一轮的id生成过程。
 43      * 
 44      * 我们知道,要从数据库中确定一个值,则必须确定其“行”和“列”。JPA自动产生的t_id_generator只有两列。当然,如果该表
 45      * 为n个表产生id,则会在t_id_generator表中保存“n行2列”。
 46      * 那么,如何从数据表t_id_generator中确定出seed_id用于为Customer实体计算id呢??JPA会依据Customer实体的
 47      * @TableGenerator 属性值来依据下面的规则的到seed_id:
 48      *     ③、valueColumnName 属性指定了seed_id的列名。valueColumnName="PK_VALUE"也就是指定了
 49      *        seed_id位于PK_VALUE列中。同时,规定了这一列必须是数值型(int,long等)。
 50      *             剩下的任务就是如何从n行中确定出是哪一行??
 51      *     ④、pkColumnName="PK_NAME",pkColumnValue="seed_t_customer_id" 两个一起来确定具体的行:
 52      *            在PK_NAME列中,值为seed_t_customer_id的那一行。
 53      *     ⑤、由上面③和④中确定出来的“行”和“列”就可以得到一个int型的整数值。这个值就是first_id。
 54      * 
 55      * 注意:我们的数据库中可以没有t_id_generator这张表,JPA会自动帮助我们完成该表的创建工作。自动创建的表只有两列:
 56      * PK_NAME(VARCHAR)和PK_VALUE(int)。同时会自动添加一条记录(seed_t_customer_id, 51) 依据优化策略的不同,辅助表中记录的数值有区别
 57      */
 58     @TableGenerator(name="ID_GENERATOR",
 59             table="t_id_generator",
 60             pkColumnName="PK_NAME",
 61             pkColumnValue="seedId_t_customer",
 62             valueColumnName="PK_VALUE",
 63             allocationSize=20,
 64             initialValue=10
 65             )
 66     @GeneratedValue(strategy=GenerationType.TABLE, generator="ID_GENERATOR")
 67     @Id
 68     @Column(name="ID")
 69     public Integer getId() {
 70         return id;
 71     }
 72 
 73     /**
 74      * @Column 指明lastName属性映射到表的 LAST_NAME 列中
 75      * 同时还可以指定其长度、能否为null等数据限定条件
 76      */
 77     @Column(name="LAST_NAME", length=50, nullable=false)
 78     public String getLastName() {
 79         return lastName;
 80     }
 81     
 82     /**
 83      * 利用 @Temporal 来限定birthday为DATE型
 84      */
 85     @Column(name="BIRTHDAY")
 86     @Temporal(TemporalType.DATE)
 87     public Date getBirthday() {
 88         return birthday;
 89     }
 90 
 91     /*
 92      * 通过 @Column 的 columnDefinition 属性将CREATED_TIME列
 93      * 映射为“DATE”类型
 94      */
 95     @Column(name="CREATED_TIME", columnDefinition="DATE")
 96     public Date getCreatedTime() {
 97         return createdTime;
 98     }
 99     
100     /*
101      * 通过 @Column 的 columnDefinition 属性将email列
102      * 映射为“TEXT”类型
103      */
104     @Column(name="EMAIL",columnDefinition="TEXT")
105     public String getEmail() {
106         return email;
107     }
108     
109     /*
110      * 工具方法,不需要映射为数据表的一列
111      */
112     @Transient
113     public String getInfo(){
114         return "lastName: " + lastName + " email: " + email;
115     }
116 
117     @Column(name="AGE")
118     public int getAge() {
119         return age;
120     }
121 
122     @SuppressWarnings("unused")
123     private void setId(Integer id) {
124         this.id = id;
125     }
126 
127     public void setLastName(String lastName) {
128         this.lastName = lastName;
129     }
130 
131     public void setEmail(String email) {
132         this.email = email;
133     }
134 
135     public void setAge(int age) {
136         this.age = age;
137     }
138 
139     public void setBirthday(Date birthday) {
140         this.birthday = birthday;
141     }
142 
143     public void setCreatedTime(Date createdTime) {
144         this.createdTime = createdTime;
145     }
146     
147 }
Customer.java
List_2. Order作为n的一方,有对Customer的引用,需要配置关联关系
 1 package com.magicode.jpa.many2one;
 2 
 3 import javax.persistence.Column;
 4 import javax.persistence.Entity;
 5 import javax.persistence.FetchType;
 6 import javax.persistence.GeneratedValue;
 7 import javax.persistence.GenerationType;
 8 import javax.persistence.Id;
 9 import javax.persistence.JoinColumn;
10 import javax.persistence.ManyToOne;
11 import javax.persistence.Table;
12 import javax.persistence.TableGenerator;
13 
14 import com.magicode.jpa.helloworld.Customer;
15 
16 @Table(name="t_order")
17 @Entity
18 public class Order {
19     
20     private Integer id;
21     private String orderName;
22     
23     private Customer customer;
24     
25     @TableGenerator(name="order_id_generator",
26             table="t_id_generator",
27             pkColumnName="PK_NAME",
28             pkColumnValue="seedId_t_order",
29             valueColumnName="PK_VALUE",
30             initialValue=0,
31             allocationSize=20)
32     @GeneratedValue(generator="order_id_generator", strategy=GenerationType.TABLE)
33     @Id
34     @Column(name="ID")
35     public Integer getId() {
36         return id;
37     }
38     
39     @Column(name="ORDER_NAME")
40     public String getOrderName() {
41         return orderName;
42     }
43     
44     /**
45      * 1、通过 @ManyToOne 来配置单向多对一的关联关系,同时可以配置fetch=FetchType.LAZY
46      * 来指定懒加载查询策略;
47      * 2、@JoinColumn来映射外键
48      */
49     @ManyToOne(fetch=FetchType.LAZY)
50     @JoinColumn(name="CUSTOMER_ID")
51     public Customer getCustomer() {
52         return customer;
53     }
54 
55     public void setCustomer(Customer customer) {
56         this.customer = customer;
57     }
58 
59     @SuppressWarnings("unused")
60     private void setId(Integer id) {
61         this.id = id;
62     }
63     
64     public void setOrderName(String orderName) {
65         this.orderName = orderName;
66     }
67 
68 }
List_3. persistence.xml的配置文件
 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <persistence version="2.0"
 3     xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4     xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
 5 
 6     <!-- 注意这里的 persistence-unit标签的name属性值,main函数中会用到它 -->
 7     <persistence-unit name="jpa-1" transaction-type="RESOURCE_LOCAL">
 8 
 9         <!-- 配置使用什么样的ORM产品作为JPA的实现 
10             1、实际上配置的是 javax.persistence.spi.PersistenceProvider 接口的实现类 
11             2、若JPA项目中只有一个JPA的实现产品,则可以不配置provider节点
12         -->
13         <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
14 
15         <!-- 添加持久化类 -->
16         <class>com.magicode.jpa.helloworld.Customer</class>
17         <class>com.magicode.jpa.many2one.Order</class>
18 
19         <properties>
20             <!-- 连接数据库的基本信息 -->
21             <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
22             <property name="javax.persistence.jdbc.url" value="jdbc:mysql:///jpa" />
23             <property name="javax.persistence.jdbc.user" value="root" />
24             <property name="javax.persistence.jdbc.password" value="tiger123" />
25 
26             <!-- 配置JPA实现产品的基本属性:配置Hibernate的基本属性 -->
27             <property name="hibernate.format_sql" value="true" />
28             <property name="hibernate.show_sql" value="true" />
29             <property name="hibernate.hbm2ddl.auto" value="update" />
30             <!-- 
31                 Setting is relevant when using @GeneratedValue. 
32                 It indicates whether or not the new IdentifierGenerator implementations 
33                 are used for javax.persistence.GenerationType.AUTO, 
34                 javax.persistence.GenerationType.TABLE and 
35                 javax.persistence.GenerationType.SEQUENCE. 
36                 Default to false to keep backward compatibility.
37              -->
38             <property name="hibernate.id.new_generator_mappings" value="true"/>
39 
40         </properties>
41 
42     </persistence-unit>
43 </persistence>
List_4. 测试方法分别测试了增、删、改、查
  1 package com.magicode.jpa.many2one;
  2 
  3 import java.util.Date;
  4 
  5 import javax.persistence.EntityManager;
  6 import javax.persistence.EntityManagerFactory;
  7 import javax.persistence.EntityTransaction;
  8 import javax.persistence.Persistence;
  9 
 10 import org.junit.After;
 11 import org.junit.Before;
 12 import org.junit.Test;
 13 
 14 import com.magicode.jpa.helloworld.Customer;
 15 
 16 public class Many2OneTest {
 17     
 18     EntityManagerFactory emf = null;
 19     EntityManager em = null;
 20     EntityTransaction transaction = null;
 21     
 22     @Before
 23     public void before(){
 24         emf = Persistence.createEntityManagerFactory("jpa-1");
 25         em = emf.createEntityManager();
 26         transaction = em.getTransaction();
 27         transaction.begin();
 28     }
 29     
 30     @After
 31     public void after(){
 32         transaction.commit();
 33         em.close();
 34         emf.close();
 35     }
 36     
 37     /**
 38      * 先持久化 1 的一方,后持久化 n 的一方会少发送两条update SQL语句
 39      */
 40     @Test
 41     public void testPersist(){
 42         
 43         for(int i = 0; i < 3; i++){
 44             char c = (char) (‘A‘ + i);
 45             String strName = (" " + c + c).trim();
 46             int age = 25 + i;
 47             
 48             Customer customer = new Customer();
 49             customer.setAge(age);
 50             customer.setEmail(strName + "@163.com");
 51             customer.setLastName(strName);
 52             customer.setBirthday(new Date());
 53             customer.setCreatedTime(new Date());
 54             
 55             Order order1 = new Order();
 56             order1.setOrderName("O-" + strName + "-1");
 57             
 58             Order order2 = new Order();
 59             order2.setOrderName("O-" + strName + "-2");
 60             
 61             //设置关联关系
 62             order1.setCustomer(customer);
 63             order2.setCustomer(customer);
 64             
 65             //持久化操作
 66             em.persist(customer);
 67             em.persist(order1);
 68             em.persist(order2);
 69         }
 70     }
 71     
 72     /**
 73      * 查询单向多对一关联关系的时候,默认情况下采用的是left outer join策略。
 74      * 可以通过 @ManyToOne(fetch=FetchType.LAZY) 来配置为懒加载查询策略
 75      */
 76     @Test
 77     public void testFind(){
 78         Order order = em.find(Order.class, 1);
 79         
 80         System.out.println("-----1------");
 81         System.out.println("orderName: " + order.getOrderName());
 82         
 83         System.out.println("-----2------");
 84         System.out.println("order.customer.email: " + order.getCustomer().getEmail());
 85     }
 86     
 87     @Test
 88     public void testRemove(){
 89         //删除多的一端可以随便删除
 90 //        Order order = em.find(Order.class, 1);
 91 //        em.remove(order);
 92         
 93         //删除1的一端的时候,如果还有多的一端引用它,则会删除失败
 94         Customer customer = em.find(Customer.class, 11);
 95         em.remove(customer);
 96     }
 97     
 98     @Test
 99     public void testUpdate(){
100         Customer customer = em.find(Customer.class, 12);
101         customer.setAge(1000);
102         
103         Order order = em.find(Order.class, 5);
104         order.setOrderName("OOOO");
105         order.getCustomer().setAge(1000);
106     }
107 }

 

6、JPA_映射单向多对一的关联关系(n的一方有1的引用,1的一方没有n的集合属性)

标签:

原文地址:http://www.cnblogs.com/lj95801/p/5005440.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!