其實在 Spring 上要做 JOIN,還挺麻煩的…
如果可以的話,我覺得能不要做就不要做比較好 XD
不過真的需要的時候,如果是需要 SELECT 時做 JOIN,推薦可以參考 [1-2] 的說明。
實務應用的話,假設以 logback 輸出到 SQL Server 的格式作為範例
想要一次取得整個 log 包含相關的 property 和 stack trace,以下的 Entity 範例是能夠套用。
logback 輸出 SQL Server 的 schema
schema 可以參考 [3],以下為 schema 的內容:
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
@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
@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
@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
@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 會用很沒效率的方式在刪除關聯
而且某些狀況下有可能會刪除沒有預期要刪除的資料。
沒有留言:
張貼留言