Google Code Prettify

2017年1月25日 星期三

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


在看過之前一對多多對多的例子後,現在把兩個合在一起,現在要把 Appointment 類別完全依它與其它 Entity 類別的關係如上圖的建立好,Appointment 修改如下:
 1 @Entity
 2 @Table(
 3     name="APPOINTMENT",
 4     uniqueConstraints = {
 5         @UniqueConstraint(columnNames = "SYSID")
 6     })
 7 @Data
 8 public class Appointment implements Serializable {
 9     private static final long serialVersionUID = -3781642274581820116L;
10     
11     @Id
12     @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="SEQ_APPOINTMENT")
13     @SequenceGenerator(name="SEQ_APPOINTMENT", sequenceName="SEQ_APPOINTMENT", initialValue=1, allocationSize=1)
14     private Long sysid;
15     
16     @ManyToOne(fetch = FetchType.LAZY)
17     @JoinColumn(name = "EMAIL", insertable = false, updatable = false)
18     private Users users;
19     
20     @Column(name = "NAME", length = 30)
21     private String name;
22     
23     @ManyToOne(fetch = FetchType.LAZY)
24     @JoinColumn(name = "RESTAURANT_SYSID", insertable = false, updatable = false)
25     private Restaurant restaurant;
26     
27     @Column(name = "DESCRIPTION", length = 500)
28     private String description;
29     
30     @Column(name = "PHOTO")
31     private byte[] photo;
32     
33     @Column(name = "PEOPLE")
34     private Integer people;
35     
36     @Column(name = "WILLPAY")
37     private Integer willPay;
38     
39     @Column(name = "PAYKIND", length = 2)
40     private String payKind;
41     
42     @Column(name = "CANCEL", length = 1)
43     private String cancel;
44     
45     @Column(name = "HTIME")
46     private Date htime;
47     
48     @Column(name = "CTIME")
49     private Date ctime;
50 
51     @Override
52     public String toString() {
53         return "Appointment [sysid=" + sysid + ", name=" + name + ", description=" + description + ", photo="
54                 + Arrays.toString(photo) + ", people=" + people + ", willPay=" + willPay + ", payKind=" + payKind
55                 + ", cancel=" + cancel + ", htime=" + htime + ", ctime=" + ctime + "]";
56     }
57     
58     @ManyToMany(fetch = FetchType.LAZY)
59     @JoinTable(name = "PARTICIPANT",
60         joinColumns = { @JoinColumn(name = "APPOINTMENT_SYSID") },
61         inverseJoinColumns = { @JoinColumn (name = "EMAIL") })
62     private List<Users> particpants;  
63 }
  • 第 16~18 行,定義 Appointment 和 Users 的多對一關係。
  • 第 23~25 行,定義 Appointment 和 Restaurant 的多對一關係,特別注意第 24 行的 RESTAURANT_SYSID,這是 table APPOINTMENT 中關係到 table RESTAURANT 的欄位。
  • 第 58~62 行,定義 Appointment - Talking - Users 即參與者的多對多關係。
一個 Entity 即使定義了這麼複雜的關係,還是可以執行,不會有問題的,但是,後面會說明這樣定義的一些限制,先來看一下怎麼在 table APPOINTMENT 中新增一筆資料。
    @Test
    public void testCreate() throws IOException {
        //讀檔
        Path path = Paths.get("E:/55047183.jpg");
        byte[] photo = Files.readAllBytes(path);

        //寫入DB
        Appointment appointment = new Appointment();
        
        Users user = daoUsers.findOne("hi.steven@gmail.com");
        
        Restaurant restaurant = daoRestaurant.find(2L);
        
        appointment.setUsers(user);
        appointment.setName("除夕圍爐");
        appointment.setRestaurant(restaurant);
        appointment.setDescription("除夕找人聊天");
        appointment.setPhoto(photo);
        appointment.setPeople(2);
        appointment.setWillPay(500);
        appointment.setPayKind("A");
        appointment.setCancel("N");
        appointment.setHtime(Calendar.getInstance().getTime());
        appointment.setCtime(Calendar.getInstance().getTime());
        
        int count = daoApp.create(appointment);
        assertEquals(1, count);
    }
在 Entity Appointment 中,並沒有定義 table APPOINTMENT 的 EMAIL、RESTAURANT_SYSID 兩個欄位,代替的是 Users 及 Restaurant 兩個 Entity,所以在新增資料時,就可以看到如上面紅色的程式碼,設定到 appointment 的是這兩個 Entity 的物件。
  • DAO
public List<Appointment> find(Users user) {
        TypedQuery<Appointment> query = manager.createQuery("select a from Appointment a where a.users = :user ", Appointment.class);
        query.setParameter("user", user);
        return query.getResultList();
    }
  • Unit Test
    @Transactional
    @Test
    public void testFindUser() throws IOException {
        Users user = daoUsers.findOne("hi.steven@gmail.com");
        
        List<Appointment> app = daoApp.find(user);

        for(Appointment a:app) {
            System.out.println(a.getParticpants().toString());
        }
    }
在 Entity Appointment 中沒有 email 欄位,要搜尋是那個使用者起的飯局,就要用該使用者的 Users 物件,如上 DAO 的 JPQL 所示。第二段的 Unit Test 程式也可以看到傳入 DAO 的是事先查詢出來的 Users 物件。從這裡可以看到,在設計 Entity 時,可能不一定要完全按照資料庫的關聯來建立,還要考慮到使用 DAO 時的方便性,以這個例子來說,或許可以 email 變數來代表 EMAIL 欄位,而不要用 Entity Users,雖然會無法由 Entity 中看出資料庫 table 間的關係,但是使用上比較方便的話,也是無妨。





【萬年五K的圍棋 - 星位-小馬步掛】
不管持黑子或白子,我佈局習慣下星位,這時候就會常遇到對手用小馬步掛來搶地盤,通常我就如下圖所示的下: (星位-小馬步掛-一間跳)

這樣下很簡單的黑白雙方各據一方,而且白子下 (4) 之後,黑子又可以有先手到別的戰場上去。問題是,有時候因為週邊情勢的關係,不希望白可以 (4) 佔有邊上領地,就會使用一間夾,如下: (星位-小馬步掛-一間夾)

這是其中一種最常遇到的變化,(7) 衝一手很重要,因為可以讓白棋留下缺陷。

沒有留言:

張貼留言