我是靠谱客的博主 喜悦唇彩,最近开发中收集的这篇文章主要介绍Spring Data Jpa---EntityManager属性与属性值的映射演示注意结果:数据都赋值到正确的属性上面,觉得挺不错的,现在分享给大家,希望可以做个参考。
概述
在开发中使用JPA作为项目的持久层框架,在联表查询查询的时候多半会用到EntityManager这个类。
String sql = "SELECT xxx, xxx, xxx FROM x a JOIN y b ON x.id = y.id";
Query nativeQuery = em.createNativeQuery(sql);
List<Object[]> resultList = nativeQuery.getResultList();
大概是这种形式,Object数组里面的值与sql里面写的列名对应。
for (Object[] item : resultList) {
类 obj = new 类();
obj.setXXX(item[0]);
obj.setYYY(item[1]);
...
}
最后一个一个的赋值到类的属性里面去,如果你查询的字段有二三十个的话,赋值语句将会有二三十条(不想写这么多,而且还可能写漏)。
但是,查询的结果与你select的列一致,而我们类属性的定义一般也跟数据库表的列一致,只不过Java里面使用小驼峰,数据库使用下划线。
既然一致,我们就可以通过反射为我们Java类的属性赋值,而不用一个一个的去set。
这是赋值用到的工具类,可以直接拿来用
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
/**
* Created with IntelliJ IDEA.
*
* @auther: lkz
* @date: 2021/02/27
* @version: 1.0
* @description:
*/
public class BeanUtil {
/**
* source的值顺序需要与columns的列名对应
* @param columns select语句选择的列
* @param target 要赋值的对象的类型
* @param source 数据
* @return
* @throws IllegalAccessException
* @throws InstantiationException
*/
public static Object copyProperties(String columns, Class target, Object[] source) {
return copyProperties(columns, null, target, source);
}
/**
*
* @param columns
* @param prefix 只映射columns中以${prefix}开头的列
* @param target
* @param source
* @return
*/
public static Object copyProperties(String columns, String prefix, Class target, Object[] source) {
// 去空格 根据逗号分割
String[] tempArr = columns.replace(" ", "").split(",");
List<String> columnNameArr = new ArrayList<>();
for (String item : tempArr) {
int index = -1;
while ((index = item.indexOf('_')) != -1) {
if (index != -1) {// 如果有下划线 把下划线后面的字母变为大写
StringBuilder stringBuilder = new StringBuilder(item);
// 转为大写 英文字母大写和小写的ASCII码差了32
// 根据这个性质可以使用异或 无需判断
char ch = (char) (stringBuilder.charAt(index + 1) ^ 32);
item = stringBuilder.replace(index, index + 2, String.valueOf(ch)).toString();
}
}
columnNameArr.add(item);
}
// 实例化该类型
Object o = null;
try {
o = target.newInstance();
} catch (InstantiationException e) {
System.out.println("实例化出现错误");
e.printStackTrace();
} catch (IllegalAccessException e) {
System.out.println("参数错误");
e.printStackTrace();
}
// 赋值
for (int i = 0; i < columnNameArr.size(); ++i) {
String columnName = columnNameArr.get(i);
int index = -1;
if (prefix != null) {
if (columnName.startsWith(prefix)) {
// 删除前缀
columnName = columnName.replaceFirst(prefix, "");
} else {
continue;
}
}
try {
o = getAndSet(columnName, target, o, source[i]);
} catch (NoSuchFieldException e) {
// 第一次找不到先去找父类
// 一般我们会把表中id、created_time、created_by、modified_by、modified_time这些字段定义在BaseEntity
// 其他类继承BaseEntity,可以减少代码重复
// 这样的话有一些找不到的字段就有必要去父类找找
// 实际开发过程中 与数据库对应的实体类不会有很多层级 不会有 曾祖 -》 租 -》 父 - 》 子
// 最多 父 -》 子
// 这里默认去找一下上一层的父类
// 如果有多个层级 需要循环去找所以父类
try {
o = getAndSet(columnName, target.getSuperclass(), o, source[i]);
} catch (NoSuchFieldException noSuchFieldException) {
System.out.println("在类型 " + target +" 中, 没有属性 " + columnName);
}
}
}
return o;
}
private static Object getAndSet(String columnName, Class target, Object entity, Object source) throws NoSuchFieldException {
// 数据库的bigint对应java的BigInteger 无法直接转为Long
if (source instanceof BigInteger) {
source = ((BigInteger) source).longValue();
}
try {
// 能获取类上公有、保护、私有字段 但是不能获取父类字段
Field field = target.getDeclaredField(columnName);
if (Modifier.isStatic(field.getModifiers()) || Modifier.isStatic(field.getModifiers())) {
System.out.println("忽略static或者final修饰的字段, " + target + ", " + columnName);
return entity;
}
// 设置字段为可访问行
field.setAccessible(true);
field.set(entity, source);
} catch (IllegalAccessException e) {
System.out.println("类型赋值错误");
e.printStackTrace();
}
return entity;
}
}
演示
首先建立两张表
test_a
/*
Navicat Premium Data Transfer
Source Server : 本地
Source Server Type : MySQL
Source Server Version : 80022
Source Host : localhost:3306
Source Schema : test
Target Server Type : MySQL
Target Server Version : 80022
File Encoding : 65001
Date: 06/03/2021 16:36:12
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for test_a
-- ----------------------------
DROP TABLE IF EXISTS `test_a`;
CREATE TABLE `test_a` (
`id` bigint(0) NOT NULL AUTO_INCREMENT,
`num` int(0) NULL DEFAULT NULL,
`str_x_y` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
`time` datetime(0) NULL DEFAULT NULL,
`time1` date NULL DEFAULT NULL,
`double_num` double NULL DEFAULT NULL,
`float_num` float NULL DEFAULT NULL,
`message` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of test_a
-- ----------------------------
INSERT INTO `test_a` VALUES (1, 1, 'aaa', '2021-03-06 13:57:49', '2021-03-06', 1, 1, 'aaaaa');
INSERT INTO `test_a` VALUES (2, 2, 'bbb', '2021-03-06 13:58:19', '2021-03-06', 2, 2, 'bbbbbb');
INSERT INTO `test_a` VALUES (3, 3, 'ccc', '2021-03-06 13:58:44', '2021-03-06', 3, 3, 'cccccc');
INSERT INTO `test_a` VALUES (4, 4, 'ddd', '2021-03-06 13:59:03', '2021-03-06', 4, 4, 'ddddd');
SET FOREIGN_KEY_CHECKS = 1;
test_b
/*
Navicat Premium Data Transfer
Source Server : 本地
Source Server Type : MySQL
Source Server Version : 80022
Source Host : localhost:3306
Source Schema : test
Target Server Type : MySQL
Target Server Version : 80022
File Encoding : 65001
Date: 06/03/2021 16:37:21
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for test_b
-- ----------------------------
DROP TABLE IF EXISTS `test_b`;
CREATE TABLE `test_b` (
`id` bigint(0) NOT NULL AUTO_INCREMENT,
`str_x` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of test_b
-- ----------------------------
INSERT INTO `test_b` VALUES (1, 'aa');
INSERT INTO `test_b` VALUES (2, 'bb');
INSERT INTO `test_b` VALUES (3, 'cc');
INSERT INTO `test_b` VALUES (4, 'dd');
SET FOREIGN_KEY_CHECKS = 1;
两个实体类
@Data
public class TestA {
private Long id;
private Integer num;
private String strXY;
private Date time;
private Date time1;
private Double doubleNum;
private Float floatNum;
private String message;
}
@Data
public class TestB {
private Long id;
private String strX;
}
现在要做的就是两张表的联查
因为列名重复的话要取别名,我们映射的话就不需要。
所以copyColumns和exeColumns是有区别的,执行用了exeColumns,映射用了copyColumns。
然后还给表取了别名,列名也加上了表名作为前缀,映射的时候要带上这个前缀才能正确处理它们之间的关系。
@RestController
public class controller {
@Resource
private EntityManager em;
@GetMapping("/get")
public List<Test> get() {
String copyColumns = "a.id, a.num, a.str_x_y, a.time, a.time1, a.double_num, a.float_num, a.message, b.id, b.str_x ";
String exeColumns = "a.id, a.num, a.str_x_y, a.time, a.time1, a.double_num, a.float_num, a.message, b.id bId, b.str_x ";
String sql = "SELECT " + exeColumns + "FROM test_a a JOIN test_b b ON a.id = b.id";
Query nativeQuery = em.createNativeQuery(sql);
List<Object[]> resultList = nativeQuery.getResultList();
List<Test> list = new ArrayList<>();
for (int i = 0; i < resultList.size(); ++i) {
TestA testA = (TestA) BeanUtil.copyProperties(copyColumns, "a.", TestA.class, resultList.get(i));
TestB testB = (TestB) BeanUtil.copyProperties(copyColumns, "b.", TestB.class, resultList.get(i));
Test test = new Test();
test.setA(testA);
test.setB(testB);
list.add(test);
}
return list;
}
}
注意
结果:数据都赋值到正确的属性上面
最后
以上就是喜悦唇彩为你收集整理的Spring Data Jpa---EntityManager属性与属性值的映射演示注意结果:数据都赋值到正确的属性上面的全部内容,希望文章能够帮你解决Spring Data Jpa---EntityManager属性与属性值的映射演示注意结果:数据都赋值到正确的属性上面所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复