Criteria API结合Specification动态查询主表和复合主键从表数据?

Criteria API 实现主表和复合主键的从表的左外连接查询,并使用Specification动态拼接条件

有两个表 t_com,t_kbn
t_com有如下字段
com_id,com_no,com_kbn1,com_kbn2,com_kbn3,com_kbn4,com_kbn5,com_name 所有字段都是String类型 其中com_id,com_no为联合主键
t_kbn是字典表,有如下字段
kbn,kbn_id,kbn_name,kbn_name2 所有字段都是String类型 其中kbn和kbn_id为联合主键
t_com表的com_kbn1,com_kbn2,com_kbn3,com_kbn4,com_kbn5和t_kbn的kbn_id有关联,
用Criteria API结合Specification 实现主表 t_com的com_kbn1,com_kbn2,com_kbn3,com_kbn4,com_kbn5 左外连接t_kbn的kbn_id进行查询,
动态拼接查询条件com_name,返回t_com的所有字段和t_kbn的kbn_name字段

阅读 759
avatarAI BotBETA
### 回答

要实现使用Criteria API结合Specification进行主表 `t_com` 和复合主键从表 `t_kbn` 的左外连接查询,并动态拼接查询条件 `com_name`,返回 `t_com` 的所有字段和 `t_kbn` 的 `kbn_name` 字段,可以按照以下步骤进行:

1. **定义实体类**:
    - `TCom` 类,包含 `com_id`, `com_no`, `com_kbn1`, `com_kbn2`, `com_kbn3`, `com_kbn4`, `com_kbn5`, `com_name` 字段,并设置复合主键。
    - `TKbn` 类,包含 `kbn`, `kbn_id`, `kbn_name`, `kbn_name2` 字段,并设置复合主键。

2. **创建 `Specification`**:
    - 使用 `Specification` 来动态拼接查询条件,比如 `com_name`。

3. **使用 `CriteriaBuilder` 和 `CriteriaQuery`**:
    - 创建 `CriteriaBuilder` 实例。
    - 创建 `CriteriaQuery` 实例,指定查询的根(`Root<TCom>`)。
    - 使用 `join` 方法进行左外连接,连接 `t_com` 和 `t_kbn` 表。
    - 设置查询的选择列表,包含 `t_com` 的所有字段和 `t_kbn` 的 `kbn_name` 字段。
    - 添加查询条件,包括动态拼接的条件。

4. **执行查询**:
    - 使用 `EntityManager` 执行查询并获取结果。

以下是一个示例代码:

import javax.persistence.*;
import javax.persistence.criteria.*;
import java.util.*;

// 假设已经定义了 TCom 和 TKbn 实体类

public class DynamicQueryExample {

public List<Object[]> findComWithKbnName(EntityManager em, String comName) {
    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<Object[]> cq = cb.createQuery(Object[].class);

    Root<TCom> comRoot = cq.from(TCom.class);

    // 左外连接 t_kbn 表,根据 com_kbn1, com_kbn2, ..., com_kbn5
    List<Join<TCom, TKbn>> joins = new ArrayList<>();
    for (int i = 1; i <= 5; i++) {
        String kbnFieldName = "com_kbn" + i;
        Join<TCom, TKbn> join = comRoot.join("kbn" + i, JoinType.LEFT); // 假设在 TCom 中有对应的关联关系
        joins.add(join);
        cq.multiselect(
            comRoot.get("com_id"),
            comRoot.get("com_no"),
            // ... 选择 t_com 的其他字段
            comRoot.get("com_name"),
            // 尝试从每个 join 中获取 kbn_name,这里需要处理多个可能的匹配情况
            // 简单起见,这里只选择第一个 join 的 kbn_name 作为示例
            // 实际应用中可能需要根据业务逻辑进行更复杂的处理
            cb.coalesce(join.get("kbn_name"), cb.literal(""))
        );
    }

    // 动态添加查询条件
    Predicate namePredicate = comName != null ? cb.equal(comRoot.get("com_name"), comName) : cb.conjunction();

    cq.where(namePredicate);

    TypedQuery<Object[]> query = em.createQuery(cq);
    return query.getResultList();
}

}

// 注意:
// 1. 上述代码中的关联关系(如 comRoot.join("kbn" + i, JoinType.LEFT))需要在实际实体类中定义。
// 2. 由于 t_com 的多个字段都与 t_kbn 有外键关系,这里的处理较为简化,实际业务中可能需要更复杂的逻辑来处理多个可能的匹配。
// 3. 使用 cb.coalesce 来处理可能的 null 值,确保查询结果中 kbn_name 字段不为 null。


**注意**:上述代码是一个简化的示例,用于说明如何使用Criteria API和Specification进行动态查询。在实际应用中,需要根据具体的实体类定义和业务逻辑进行适当调整。特别是处理多个可能的匹配和关联关系时,可能需要更复杂的逻辑。
1 个回答

项目目录结构

src/
├── main/
│   ├── java/
│   │   └── com/
│   │       └── example/
│   │           ├── Application.java
│   │           ├── config/
│   │           │   └── JpaConfig.java
│   │           ├── controller/
│   │           │   └── ComController.java
│   │           ├── entity/
│   │           │   ├── Com.java
│   │           │   └── Kbn.java
│   │           ├── repository/
│   │           │   ├── ComRepository.java
│   │           │   └── KbnRepository.java
│   │           ├── service/
│   │           │   └── ComService.java
│   │           └── specification/
│   │               └── ComSpecification.java
│   └── resources/
│       └── application.properties
└── test/
    └── java/
        └── com/
            └── example/
                └── ApplicationTests.java

代码文件

Application.java

package com.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

JpaConfig.java

package com.example.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

@Configuration
@EnableJpaRepositories(basePackages = "com.example.repository")
public class JpaConfig {
}

ComController.java

package com.example.controller;

import com.example.entity.Com;
import com.example.service.ComService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
public class ComController {

    @Autowired
    private ComService comService;

    @GetMapping("/coms")
    public List<Com> getComs(@RequestParam(required = false) String comName) {
        return comService.findComs(comName);
    }
}

Com.java

package com.example.entity;

import javax.persistence.*;
import java.util.Objects;

@Entity
@Table(name = "t_com")
public class Com {

    @EmbeddedId
    private ComId id;

    @Column(name = "com_kbn1")
    private String comKbn1;

    @Column(name = "com_kbn2")
    private String comKbn2;

    @Column(name = "com_kbn3")
    private String comKbn3;

    @Column(name = "com_kbn4")
    private String comKbn4;

    @Column(name = "com_kbn5")
    private String comKbn5;

    @Column(name = "com_name")
    private String comName;

    // Getters and setters

    @Embeddable
    public static class ComId {
        @Column(name = "com_id")
        private String comId;

        @Column(name = "com_no")
        private String comNo;

        // Getters and setters, equals, and hashCode
    }
}

Kbn.java

package com.example.entity;

import javax.persistence.*;
import java.util.Objects;

@Entity
@Table(name = "t_kbn")
public class Kbn {

    @EmbeddedId
    private KbnId id;

    @Column(name = "kbn_name")
    private String kbnName;

    @Column(name = "kbn_name2")
    private String kbnName2;

    // Getters and setters

    @Embeddable
    public static class KbnId {
        @Column(name = "kbn")
        private String kbn;

        @Column(name = "kbn_id")
        private String kbnId;

        // Getters and setters, equals, and hashCode
    }
}

ComRepository.java

package com.example.repository;

import com.example.entity.Com;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;

public interface ComRepository extends JpaRepository<Com, Com.ComId>, JpaSpecificationExecutor<Com> {
}

KbnRepository.java

package com.example.repository;

import com.example.entity.Kbn;
import org.springframework.data.jpa.repository.JpaRepository;

public interface KbnRepository extends JpaRepository<Kbn, Kbn.KbnId> {
}

ComService.java

package com.example.service;

import com.example.entity.Com;
import com.example.repository.ComRepository;
import com.example.specification.ComSpecification;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class ComService {

    @Autowired
    private ComRepository comRepository;

    public List<Com> findComs(String comName) {
        return comRepository.findAll(ComSpecification.comNameContains(comName));
    }
}

ComSpecification.java

package com.example.specification;

import com.example.entity.Com;
import org.springframework.data.jpa.domain.Specification;

import javax.persistence.criteria.JoinType;

public class ComSpecification {

    public static Specification<Com> comNameContains(String comName) {
        return (root, query, criteriaBuilder) -> {
            if (comName == null || comName.isEmpty()) {
                return criteriaBuilder.conjunction();
            }
            return criteriaBuilder.like(root.get("comName"), "%" + comName + "%");
        };
    }

    public static Specification<Com> joinWithKbn() {
        return (root, query, criteriaBuilder) -> {
            root.join("comKbn1", JoinType.LEFT).on(criteriaBuilder.equal(root.get("comKbn1"), "kbnId"));
            root.join("comKbn2", JoinType.LEFT).on(criteriaBuilder.equal(root.get("comKbn2"), "kbnId"));
            root.join("comKbn3", JoinType.LEFT).on(criteriaBuilder.equal(root.get("comKbn3"), "kbnId"));
            root.join("comKbn4", JoinType.LEFT).on(criteriaBuilder.equal(root.get("comKbn4"), "kbnId"));
            root.join("comKbn5", JoinType.LEFT).on(criteriaBuilder.equal(root.get("comKbn5"), "kbnId"));
            return criteriaBuilder.conjunction();
        };
    }
}

application.properties

spring.datasource.url=jdbc:mysql://localhost:3306/yourdatabase
spring.datasource.username=yourusername
spring.datasource.password=yourpassword
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true

ApplicationTests.java

package com.example;

import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class ApplicationTests {

    @Test
    void contextLoads() {
    }
}
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏