其實在 Spring 上要做 JOIN,還挺麻煩的…
如果可以的話,我覺得能不要做就不要做比較好 XD
不過真的需要的時候,如果是需要 SELECT 時做 JOIN,推薦可以參考 [1-2] 的說明。
實務應用的話,假設以 logback 輸出到 SQL Server 的格式作為範例
想要一次取得整個 log 包含相關的 property 和 stack trace,以下的 Entity 範例是能夠套用。
logback 輸出 SQL Server 的 schema
schema 可以參考 [3],以下為 schema 的內容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
CREATE TABLE logging_event ( timestmp DECIMAL (20) NOT NULL , formatted_message VARCHAR (4000) NOT NULL , logger_name VARCHAR (254) NOT NULL , level_string VARCHAR (254) NOT NULL , thread_name VARCHAR (254), reference_flag SMALLINT , arg0 VARCHAR (254), arg1 VARCHAR (254), arg2 VARCHAR (254), arg3 VARCHAR (254), caller_filename VARCHAR (254) NOT NULL , caller_class VARCHAR (254) NOT NULL , caller_method VARCHAR (254) NOT NULL , caller_line CHAR (4) NOT NULL , event_id DECIMAL (40) NOT NULL identity, PRIMARY KEY (event_id) ) CREATE TABLE logging_event_property ( event_id DECIMAL (40) NOT NULL , mapped_key VARCHAR (254) NOT NULL , mapped_value VARCHAR (1024), PRIMARY KEY (event_id, mapped_key), FOREIGN KEY (event_id) REFERENCES logging_event(event_id) ) CREATE TABLE logging_event_exception ( event_id DECIMAL (40) NOT NULL , i SMALLINT NOT NULL , trace_line VARCHAR (254) NOT NULL , PRIMARY KEY (event_id, i), FOREIGN KEY (event_id) REFERENCES logging_event(event_id) ) |
Entity
假設我的 Entity 物件名字是 Activity、ActivityProperty、ActivityStackTrace,分別定義如下:
Activity
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
@Entity (name = "logging_event" ) public class Activity implements Serializable { @Id @Column (name = "event_id" ) private Long eventId; @Column (name = "timestmp" ) private Long timestmp; @Column (name = "formatted_message" ) private String message; @Column (name = "logger_name" ) private String logger; @Column (name = "level_string" ) private String level; @Column (name = "thread_name" ) private String thread; @Column (name = "reference_flag" ) private Integer reference; @Column (name = "arg0" ) private String arg0; @Column (name = "arg1" ) private String arg1; @Column (name = "arg2" ) private String arg2; @Column (name = "arg3" ) private String arg3; @Column (name = "caller_filename" ) private String callerFile; @Column (name = "caller_class" ) private String callerClass; @Column (name = "caller_method" ) private String callerMethod; @Column (name = "caller_line" ) private String callerLine; @OneToMany ( mappedBy = "eventId" , cascade = CascadeType.ALL, fetch = FetchType.EAGER) private List<ActivityProperty> properties; @OneToMany (cascade = CascadeType.ALL) @JoinColumn (name = "event_id" , referencedColumnName = "event_id" ) @LazyCollection (LazyCollectionOption.FALSE) private List<ActivityStackTrace> stackTraces; } |
ActivityProperty
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
@Entity (name = "logging_event_property" ) public class ActivityProperty implements Serializable { private static final long serialVersionUID = - 6532428503805543364L ; @Id @Column (name = "event_id" ) private Long eventId; @Column (name = "mapped_key" ) private String key; @Column (name = "mapped_value" ) private String value; } |
ActivityStackTrace
1 2 3 4 5 6 7 8 9 10 |
@Entity (name = "logging_event_exception" ) public class ActivityStackTrace implements Serializable { private static final long serialVersionUID = - 50856985039937262L ; @EmbeddedId private ActivityStackTraceId id; @Column (name = "trace_line" ) private String line; } |
ActivityStackTraceId
1 2 3 4 5 6 7 8 9 10 |
@Embeddable public class ActivityStackTraceId implements Serializable { private static final long serialVersionUID = - 4496556483758827756L ; @Column (name = "event_id" ) private Long eventId; @Column (name = "i" ) private Integer i; } |
其中在 Activity 要連結 ActivityProperty 和 ActivityStackTrace 時,都是以 @OneToMany 來標注
用來表示一個 Activity 可以有多個 ActivityProperty 和 ActivityStackTrace。
此外,由於 ActivityStackTrace 並非是單一 ID,而是 Composite Primary Key 的形式
因此要利用 @Embeddable來組合。這部份可以參考 [4]。
同時,使用了 @Embeddable 之後,如果 JOIN 操作依然使用 mappedBy 的話,會出現 [5] 提到的錯誤
目前其實還沒有搞很懂這個錯誤是什麼意思,不過姑且使用 [5] 的作法,改成用 LazyCollection 可以解決。
未來如果有把問題搞懂的話,再回來追加補充了 @@a
除此之外,還得稍微注意一下,上述的 JOIN 寫法,有可能導致 [6] 描述的問題
也就是當要做資料刪除時,Hibernate 產生的 SQL Statement 會用很沒效率的方式在刪除關聯
而且某些狀況下有可能會刪除沒有預期要刪除的資料。
沒有留言:
張貼留言