基於代碼復用和模型分離的思想,在項目開發中使用JPA的@MappedSuperclass注解將實體類的多個屬性分別封裝到不同的非實體類中。
1.@MappedSuperclass注解只能標准在類上:@Target({java.lang.annotation.ElementType.TYPE})
2.標注為@MappedSuperclass的類將不是一個完整的實體類,他將不會映射到數據庫表,但是他的屬性都將映射到其子類的數據庫字段中。
3.標注為@MappedSuperclass的類不能再標注@Entity或@Table注解,也無需實現序列化接口。
但是如果一個標注為@MappedSuperclass的類繼承了另外一個實體類或者另外一個同樣標注了@MappedSuperclass的類的話,他將可以使用@AttributeOverride或@AttributeOverrides注解重定義其父類(無論是否是實體類)的屬性映射到數據庫表中的字段。
比如可以重定義字段名或長度等屬性,使用@AttributeOverride中的子屬性@Column進行具體的定義。
注意:對於其父類中標注@Lob注解的屬性將不能重載,並且@AttributeOverride里的@Column設置都將不起作用。
JPA規范中對@Lob注解並沒有說明不能同時標注@Column注解,但是在實際使用中Hibernate JPA不支持這中標注方式。
4.此外,這樣的類還可以直接標注@EntityListeners實體監聽器,他的作用范圍僅在其所有繼承類中,並且實體監聽器同樣可以保被其子類繼承或重載。
5.標注為@MappedSuperclass的類其屬性最好設置為protected或default類型的,以保證其同一個包下的子類可以直接調用它的屬性。便於實體監聽器或帶參數構造函數的操作。
6.由於標注為@MappedSuperclass的類將不是一個完整的實體類,因此其不能標注@Table,並且無法使用@UniqueConstraint設置字段的Unique屬性,這一點以及對屬性類型重載(如重載標注為@Lob的屬性)的支持JPA規范還有待改進。
7.可以同時標注@DiscriminatorValue注解,以設定實體子類的實體標識字段的值。該屬性一般是在實體繼承的時候使用的較多,但是在實體映射的時候可以不用設置。
8.比較實體繼承與實體映射的區別:
實體繼承的三種策略分別是:SINGLE_TABLE(所有繼承的實體都保存在同一張數據庫表中),JOINED(每個實體子類都將保存在一個單獨的表中),TABLE_PER_CLASS(有繼承關系的所有實體類都將保存在單獨的表中)。
實體映射最類似於JOINED實體繼承方式,他也是將實體子類單獨保存為一張表,但是兩者最大的區別就在於:查詢的時候JOINED使用的是多態查詢,在查詢父類時其所有實體子類的數據也將同時被查詢出,因此查詢時間和性能都將有影響。但是實體映射方式的數據庫查詢等同於沒有實體繼承關系的查詢,也就是說,他僅在實體層體現出一種繼承的關系卻並沒有在數據庫中體現這樣一種關系,他的操作都是獨立的並且將不會影響到實體子類。
P.S.文中部分語義不清或描述含糊甚至定義錯誤的,請指正,期待共同進步!
