如何使用JPA的@Formula注解


背景描述

我們經常會在項目中用到一些數據字典,在存儲和傳輸時使用Code,在前端展示時使用Name,這樣做的好處是便於系統維護,比如項目中用到了"醫院"這個名稱,如果后期需求發生變化不叫"醫院"了,改成"醫療機構",假如不使用數據字典,那么我們代碼中、數據庫中所有用到"醫院"的地方都要修改,麻煩不說,漏掉一個就是一個小Bug。在處理這個Code/Name的轉化的時候,我思考了幾種處理方式,第一種,使用@ManyToOne注解關聯字典查詢,這樣是最容易想到的方式,但是這種方式得到的結果是字典對象整體包含在查詢到的實體中,我們所需要的只是字典里的name,所以我嘗試尋找一種直接將字典表里的name映射到實體對象上的方式。第二種,使用HQL關聯查詢映射到自定義對象,這種方式可以達到我的預期,但是HQL寫起來很麻煩,尤其是當需要關聯查詢的字典特別多的時候。並且我的項目中動態用的是JPA的Specification,如果使用這種方式,那么項目中的動態查詢需要改寫,也是不小的工作量。第三種,使用@Formula注解的方式,下面重點說說這種方式。

使用介紹

@Formula的作用是計算出一個臨時的屬性值,我們可以利用它,去關聯查詢其他表中的某個字段為對象的屬性賦值,而這個屬性是不持久化到數據庫中的。

用代碼描述一下會比較直觀:

建立兩個實體類

班級字典

@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

持久層

public interface StudentRepo extends JpaRepository<Student, Long> {
    //很持久
}

控制層

@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導致的,我未能找到具體原因,所以用起來還是很不隨心,不知道大家是否有好的處理方案,歡迎指教!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM