咱们常常会在项目中用到一些数据字典,在存储和传输时使用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致使的,我未能找到具体缘由,因此用起来仍是很不随心,不知道你们是否有好的处理方案,欢迎指教!