如何使用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致使的,我未能找到具体缘由,因此用起来仍是很不随心,不知道你们是否有好的处理方案,欢迎指教!

相关文章
相关标签/搜索