咱們常常會在項目中用到一些數據字典,在存儲和傳輸時使用Code,在前端展現時使用Name,這樣作的好處是便於系統維護,好比項目中用到了"醫院"這個名稱,若是後期需求發生變化不叫"醫院"了,改爲"醫療機構",假如不使用數據字典,那麼咱們代碼中、數據庫中全部用到"醫院"的地方都要修改,麻煩不說,漏掉一個就是一個小Bug。在處理這個Code/Name的轉化的時候,我思考了幾種處理方式,第一種,使用@ManyToOne註解關聯字典查詢,這樣是最容易想到的方式,可是這種方式獲得的結果是字典對象總體包含在查詢到的實體中,咱們所須要的只是字典裏的name,因此我嘗試尋找一種直接將字典表裏的name映射到實體對象上的方式。第二種,使用HQL關聯查詢映射到自定義對象,這種方式能夠達到個人預期,可是HQL寫起來很麻煩,尤爲是當須要關聯查詢的字典特別多的時候。而且個人項目中動態用的是JPA的Specification,若是使用這種方式,那麼項目中的動態查詢須要改寫,也是不小的工做量。第三種,使用@Formula註解的方式,下面重點說說這種方式。前端
@Formula的做用是計算出一個臨時的屬性值,咱們能夠利用它,去關聯查詢其餘表中的某個字段爲對象的屬性賦值,而這個屬性是不持久化到數據庫中的。java
用代碼描述一下會比較直觀:sql
創建兩個實體類數據庫
班級字典app
@Data @Entity public class DictClass { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(nullable = false) private String classCode;//班級編號 private String className;//班級名稱 }
學生類框架
@Data @Entity public class Student { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(nullable = false) private String name; //名字 @Column(name = "CLASS_CODE") private String classCode;//班級編號 @Formula("(select d.class_name from dict_class as d where d.class_code = class_code)") private String className;//班級名稱 }
@Formula("(select d.class_name from dict_class as d where d.class_code = class_code)")意思就是從數據庫的dict_class
表中查詢到class_name
字段的數據,賦值到className
屬性上。"="後面的class_code對應的時@Column裏的class_code測試
持久層code
public interface StudentRepo extends JpaRepository<Student, Long> { //很持久 }
控制層orm
@RestController @RequestMapping("/formula") @Api(tags = "formula測試接口") public class FormulaController { @Autowired StudentRepo studentRepo; @GetMapping public List<Student> findAll(){ return studentRepo.findAll(); } }
測試一下,獲取成功對象
雖然看起來很簡單,不過仍是有好些個須要注意的地方,一言不合就失效。
1.網上好多人說@Formula必須用在屬性上,其實不是的,@Formula 要與@Id註解同時用在屬性上,或者同時用在在get方法上,不然@Formula失效。
2.若是查詢中用到了where,那麼須要給表起一個別名,不然@Formula失效。
3.@Formula與@Transient不能同時使用,不然@Formula失效。
4.使用@Formula註解的屬性不須要在數據庫表中創建與之對應的字段,而且即便創建了也沒有做用,加上@Column註解也不行。
當持久層使用原生sql查詢時,會形成NPE異常。
在持久層添加
@Query(nativeQuery = true,value = "select * from student") List<Student> findByNative();
測試一下
這彷佛是由於@Formula屏蔽了className字段,框架獲取@Column對應的name時拿到null致使的,我未能找到具體緣由,因此用起來仍是很不隨心,不知道你們是否有好的處理方案,歡迎指教!