package com.guwan.backend.builder; import jakarta.persistence.EntityManager; import jakarta.persistence.criteria.*; import java.lang.reflect.Constructor; import java.util.*; import java.util.stream.Collectors; /** * 自定义连表查询构建器 * 用于构建复杂的多表连接查询,支持指定返回字段和条件 */ public class JoinBuilder { private final Class rootClass; private final Map, JoinInfo> joins = new HashMap<>(); private final Map, List> conditions = new HashMap<>(); private Map namedSelections = new LinkedHashMap<>(); private JoinBuilder(Class rootClass) { this.rootClass = rootClass; } public static JoinBuilder from(Class rootClass) { return new JoinBuilder<>(rootClass); } /** * 添加连接表 * * @param joinClass 要连接的表实体类 * @param sourceField 主表的外键字段 * @param targetField 连接表的目标字段 */ public void join(Class joinClass, String sourceField, String targetField) { joins.put(joinClass, new JoinInfo(sourceField, targetField)); } /** * 添加等值条件 * * @param entityClass 实体类 * @param fieldName 字段名 * @param value 字段值 */ public void equal(Class entityClass, String fieldName, V value) { if (!conditions.containsKey(entityClass)) { conditions.put(entityClass, new ArrayList<>()); } conditions.get(entityClass).add(new Condition(fieldName, value, Operator.EQUAL)); } /** * 添加一个具有别名的字段选择(字符串版本) * * @param alias 字段别名 * @param entityClass 实体类 * @param fieldName 字段名称 */ public void selectAs(String alias, Class entityClass, String fieldName) { namedSelections.put(alias, new SelectionInfo(entityClass, fieldName)); } /** * 执行查询并返回结果 * @param entityManager EntityManager实例 * @return 查询结果列表 */ public List execute(EntityManager entityManager) { // 创建CriteriaBuilder CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); // 创建CriteriaQuery CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(Object[].class); // 设置根实体 Root root = criteriaQuery.from(rootClass); // 创建连接关系 Map, From> fromMap = createJoins(root, criteriaQuery); // 应用所有条件,包括表之间的连接条件和额外查询条件 List predicates = applyAllConditions(root, fromMap, criteriaBuilder); // 添加条件到查询 if (!predicates.isEmpty()) { criteriaQuery.where(criteriaBuilder.and(predicates.toArray(new Predicate[0]))); } // 设置查询结果投影 configureSelections(root, fromMap, criteriaQuery); // 执行查询并返回结果 return entityManager.createQuery(criteriaQuery).getResultList(); } public long count(EntityManager entityManager) { CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); CriteriaQuery countQuery = criteriaBuilder.createQuery(Long.class); Root root = countQuery.from(rootClass); // 创建连接关系 Map, From> fromMap = createJoins(root, countQuery); // 应用条件,包括表之间的连接条件和额外查询条件 List predicates = applyAllConditions(root, fromMap, criteriaBuilder); // 添加条件到查询 if (!predicates.isEmpty()) { countQuery.where(criteriaBuilder.and(predicates.toArray(new Predicate[0]))); } // 设置count查询 countQuery.select(criteriaBuilder.count(root)); // 执行查询并返回结果 return entityManager.createQuery(countQuery).getSingleResult(); } public List executeAndMapWithPaging(EntityManager entityManager, Class dtoClass, int page, int size) { List results = executeWithPaging(entityManager, page, size); return mapToDto(results, dtoClass); } public List executeWithPaging(EntityManager entityManager, int page, int size) { // 创建CriteriaBuilder CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); // 创建CriteriaQuery CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(Object[].class); // 设置根实体 Root root = criteriaQuery.from(rootClass); // 创建连接关系 Map, From> fromMap = createJoins(root, criteriaQuery); // 应用所有条件 List predicates = applyAllConditions(root, fromMap, criteriaBuilder); // 添加条件到查询 if (!predicates.isEmpty()) { criteriaQuery.where(criteriaBuilder.and(predicates.toArray(new Predicate[0]))); } // 设置查询结果投影 configureSelections(root, fromMap, criteriaQuery); // 创建查询并设置分页 jakarta.persistence.Query query = entityManager.createQuery(criteriaQuery); query.setFirstResult(page * size); query.setMaxResults(size); // 执行查询并返回结果 return query.getResultList(); } /** * 创建连接 - 修改为使用from而不是join */ private Map, From> createJoins(Root root, CriteriaQuery query) { Map, From> fromMap = new HashMap<>(); fromMap.put(rootClass, root); // 对于每个需要连接的表,创建一个单独的From for (Map.Entry, JoinInfo> entry : joins.entrySet()) { Class joinClass = entry.getKey(); From joinRoot = query.from(joinClass); fromMap.put(joinClass, joinRoot); } return fromMap; } /** * 应用所有条件,包括表之间的连接条件和额外查询条件 */ private List applyAllConditions(Root root, Map, From> fromMap, CriteriaBuilder criteriaBuilder) { List predicates = new ArrayList<>(); // 首先添加表连接条件 for (Map.Entry, JoinInfo> entry : joins.entrySet()) { Class joinClass = entry.getKey(); JoinInfo joinInfo = entry.getValue(); if (fromMap.containsKey(joinClass)) { From joinFrom = fromMap.get(joinClass); Predicate joinCondition = criteriaBuilder.equal( root.get(joinInfo.sourceField), joinFrom.get(joinInfo.targetField) ); predicates.add(joinCondition); } } // 然后添加普通查询条件 for (Class entityClass : conditions.keySet()) { for (Condition condition : conditions.get(entityClass)) { if (fromMap.containsKey(entityClass)) { From from = fromMap.get(entityClass); predicates.add(applyCondition(condition, from, criteriaBuilder)); } } } return predicates; } /** * 将查询结果映射到DTO对象 * @param results 查询结果 * @param dtoClass DTO类 * @param DTO类型 * @return DTO对象列表 */ public List mapToDto(List results, Class dtoClass) { try { // 获取所有字段名(顺序与查询结果一致) List fieldNames = new ArrayList<>(namedSelections.keySet()); // 获取构造函数 Class[] paramTypes = new Class[fieldNames.size()]; Arrays.fill(paramTypes, Object.class); Constructor constructor = dtoClass.getDeclaredConstructor(paramTypes); // 映射结果 return results.stream() .map(row -> { try { return constructor.newInstance(row); } catch (Exception e) { throw new RuntimeException("Failed to map result to DTO: " + e.getMessage(), e); } }) .collect(Collectors.toList()); } catch (Exception e) { throw new RuntimeException("Failed to create DTO mapper: " + e.getMessage(), e); } } /** * 配置查询结果投影 */ private void configureSelections(Root root, Map, From> fromMap, CriteriaQuery query) { if (!namedSelections.isEmpty()) { // 处理命名选择 List> selections = new ArrayList<>(); for (Map.Entry entry : namedSelections.entrySet()) { String alias = entry.getKey(); Object value = entry.getValue(); if (value instanceof SelectionInfo) { SelectionInfo info = (SelectionInfo) value; Path path; if (fromMap.containsKey(info.entityClass)) { path = fromMap.get(info.entityClass).get(info.fieldName); selections.add(path.alias(alias)); } } } if (!selections.isEmpty()) { query.multiselect(selections); return; } } } private Predicate applyCondition(Condition condition, From from, CriteriaBuilder criteriaBuilder) { switch (condition.operator) { case EQUAL: return criteriaBuilder.equal(from.get(condition.fieldName), condition.value); // 可以添加更多操作符支持,如LIKE, IN, GREATER_THAN等 default: throw new UnsupportedOperationException("Unsupported operator: " + condition.operator); } } /** * 连接信息 */ private static class JoinInfo { private final String sourceField; private final String targetField; JoinInfo(String sourceField, String targetField) { this.sourceField = sourceField; this.targetField = targetField; } } /** * 选择字段信息 */ private static class SelectionInfo { private final Class entityClass; private final String fieldName; SelectionInfo(Class entityClass, String fieldName) { this.entityClass = entityClass; this.fieldName = fieldName; } } private enum Operator { EQUAL // 可以添加更多操作符支持,如LIKE, IN, GREATER_THAN等 } private static class Condition { private final String fieldName; private final Object value; private final Operator operator; Condition(String fieldName, Object value, Operator operator) { this.fieldName = fieldName; this.value = value; this.operator = operator; } } }