• 如何使用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导致的,我未能找到具体原因,所以用起来还是很不随心,不知道大家是否有好的处理方案,欢迎指教!

  • 相关阅读:
    [华为机试] 计算二进制数中1的个数
    vector释放
    opencv findcontours内存错误
    opencv的编译安装
    opencv SVM分类器模块的简单设计
    centos7.6安装FFMpeg
    centos安装jenkins
    centos 7.6安装Java
    Centos7 忘记密码的情况下,修改root或其他用户密码
    性能测试报告
  • 原文地址:https://www.cnblogs.com/hanstrovsky/p/12977008.html
Copyright © 2020-2023  润新知