如何使用JPA的@Formula註解?

背景描述

咱們常常會在項目中用到一些數據字典,在存儲和傳輸時使用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致使的,我未能找到具體緣由,因此用起來仍是很不隨心,不知道你們是否有好的處理方案,歡迎指教!

相關文章
相關標籤/搜索