Google Code Prettify

2016年12月24日 星期六

JPA + Spring: one-to-many (I)

上一篇「JPA + Hibernate + Spring + JUnit (annotation)」已經說明了一些環境的基本設定,接下來要整理的是以 JPA annotation 進行 one-to-many 的存取。

如上圖所示,一個使用者可以開很多飯局邀請朋友加入,所以 USERS 對 APPOINTMENT 是一對多的關係,所以,先修改 class Users 如下:
 1 @Entity
 2 @Table(
 3     name="USERS",
 4     uniqueConstraints = {
 5         @UniqueConstraint(columnNames = "EMAIL")
 6     })
 7 public class Users implements Serializable {
 8     private static final long serialVersionUID = 3965333920543479036L;
 9     
10     private String email;
11     private String password;
12     private String phone1;
13     private String phone2;
14     private String nickname;
15     private String city;
16     private String gender;
17     private String birthday;
18     private String industry;
19     private String occupation;
20     private String description;
21     private Date vtime;
22     private Date ctime;
23     private Date lastLogin;
24     
25     private Set<Appointment> appointments;
26 
27     //省略    
28 
29     @OneToMany(mappedBy="users", cascade=CascadeType.ALL, fetch=FetchType.EAGER, orphanRemoval=true)
30     public Set<Appointment> getAppointments() {
31         return appointments;
32     }
33 
34     public void setAppointments(Set<Appointment> appointments) {
35         this.appointments = appointments;
36     }    
37 }
  1.  第25行: 一個人使用者可以開多個飯局,所以在 class Users 中包含一個 Set<Appointment> 或 List<Appointment> 的變數,用來指向 class Appointment,以存取 table APPOINTMENT 中的資料。
  2. 第29行: 在 getter method 前加入 @OneToMany,mappedBy 指出是要對應到那一個類別; cascade 設定兩者的關聯性,詳細會另篇說明,這裡設定為 ALL,就是所有刪除、新增等都會有關聯; fetch 有兩個值 EAGER 及 LAZY,EAGER 是在存取 Users 時,就會把相關聯的 Appintment 也抓出來,LAZY 則會等到真的要用時才到資料庫中將值取出。
測試程式會由讀取 table USERS 後,透過關聯取得該使用者的所有飯局,所以我們先為 Users 的 DAO 加一個 method - find,如下,這裡是用 EntityManager 提供的 find method 抓出資料,find method 只能以 primary key 找出資料,後面還會說明其它方式。
 1 @Repository
 2 public class UsersDAOImpl implements UsersDAO {
 3     @PersistenceContext
 4     private EntityManager manager;
 5 
 6     @Transactional
 7     public int create(Users user) {
 8         manager.persist(user);
 9         return 1;
10     }
11 
12     @Override
13     public Users find(String email) {
14         return manager.find(Users.class, email);
15     }
16 }
接下來看一下多方 (Appointment) 的類別怎麼定義。
 1 @Entity
 2 @Table(
 3     name="APPOINTMENT",
 4     uniqueConstraints = {
 5         @UniqueConstraint(columnNames = "SYSID")
 6     })
 7 public class Appointment implements Serializable {
 8     private static final long serialVersionUID = -3781642274581820116L;
 9     
11     private String name;
12     private Long restaurant_sysid;
13     private String description; 
14     private byte[] photo;
15     private Integer people;
16     private Integer willPay;
17     private String payKind;
18     private String cancel;
19     private Date htime;
20     private Date ctime;
21     
22     @ManyToOne(fetch = FetchType.LAZY)
23     @JoinColumn(name="EMAIL", insertable=false, updatable =false)
24     private Users users;
25 
26     //省略
27 
28     public Users getUsers() {
29         return users;
30     }
31     
32     public void setUsers(Users users) {
33         this.users = users;
34     }
35 }
  1. 第23行: name="EMAIL",這是指 Appointment 用那一個欄位和 Users 的 PK 有關聯。
  2. 第14行: 資料庫裡的欄位屬性是 BLOB,是檔案資料,這裡就用 byte[] 來存取。
接著看一下 Appointment 的 DAO,裡面的 find 使用了另一種讀取資料的方式,就是寫 JPQL,雖然語法和 SQL 是很類似,但還是略有不同,要注意 from 後面的 Appointment 是 class Appointment,所以大小寫要正確。
 1 @Repository
 2 public class AppointmentDAOImpl implements AppointmentDAO {
 3     @PersistenceContext
 4     private EntityManager manager;
 5 
 6     @Transactional
 7     @Override
 8     public int create(Appointment appointment) {
 9         manager.persist(appointment);
10         return 1;
11     }
12 
13     @Override
14     public Appointment find(String email) {
15         return manager.createQuery("select a from Appointment a where a.email = :email", Appointment.class).setParameter("email", email).getSingleResult();
16     }
17 }
最後當然要來測試一下啦~ 如上一篇使用 JUnit,兩個 method 都可以存取到 table APPOINTMENT 裡的資料。
 1     @Test
 2     public void testFind() throws IOException {
 3         Appointment a = daoApp.find("hi.steven@gmail.com");
 4         
 5         Path pathTo = Paths.get("E:/testFind.jpg");
 6         Files.write(pathTo, a.getPhoto(), new OpenOption[] {StandardOpenOption.CREATE, StandardOpenOption.WRITE});
 7     }
 8     
 9     @Test
10     public void testRelation() throws IOException {
11         Users u = daoUsers.find("hi.steven@gmail.com");
12         for(Appointment a:u.getAppointments()) {
13             System.out.println(a.toString());
14         }
15     }






【日劇 - 月薪嬌妻 (逃避雖可恥但有用)】
這是新垣結衣的新作,播出以來收視長紅,收視率由第一集逐步走高,到最後一集最高。劇中女主角森山美栗因為求職不順利而"逃入婚姻",引起許多不同角度的解讀,我看這部戲時想到的是從事家務也有其價值,而且這價值長期被低估,這部戲在探討的就是這個價值。當然啦~ 不管如何解讀,最重要的是看新垣結衣搞笑 ...
新垣結衣曾在 Legal High 中飾演思想左傾的年輕律師,在這部戲裡思想也略微左傾,不知道這是巧合? 還是她本人就是如此?

1 則留言: