Software entities (class, modules, functions, etc.) should be open for extension, but closed for modification. Junior programmers create simple solutions to simple problems. Senior programmers create complex solutions to complex problems. Great programmers find simple solutions to complex problems. 註1:本部落格的範例程式碼在 2015 年以前的文章中,大多是以全型空白做縮排。如需服用,請自行用文字編輯器的取代功能把全型空白取代成半型空白。
- Bertrand Meyer
- Charles Connell
註2:本部落格的內容授權請參閱部落格底部的授權宣告。
2019年1月7日 星期一
2018年11月8日 星期四
org.hibernate.QueryException: could not resolve property: “xxx”
寫 Spring Data JPA 或者 Hibernate 時很重要的一點,就是在定義 Repository 時,對應的欄位要用 Entity 裡的變數名字,而不是實際資料庫裡的資料欄位名字。這也包括了當要使用 Pageable 等物件時,物件裡宣告的欄位也要用 Entity 的變數名字。
參考資料
2018年10月23日 星期二
在 Spring Data JPA 中使用 AUTO_INCREMENT
快速紀錄~使用 @Id 和 @GeneratedValue 就可以用自動遞增的 Primary Key 了。不過如果不想要讓 Hibernate 自己產生 ID,而是直接靠資料庫自行產生的話,可以設定 @GeneratedValue 的屬性 strategy = GenerationType.IDENTITY。
參考資料
2018年5月21日 星期一
透過 Spring Data JPA 存取 DynamoDB
因為 Spring Data JPA 用來存取資料庫時很方便,然後 DynamoDB 又是屬於特別囉唆的東西,所以之前在研究 Spring Boot 時,就在想不知道 Spring 是否有支援 DynamoDB 的實作。很幸運地,社群真的有人做了 Spring Data JPA + DynamoDB [1-2] 造福大家!XD
2018年4月13日 星期五
2018年4月11日 星期三
Spring Data JPA 的 JOIN 操作
其實在 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 會用很沒效率的方式在刪除關聯
而且某些狀況下有可能會刪除沒有預期要刪除的資料。