当前位置: 首页 > 知识库问答 >
问题:

将JPA与多个AND运算结合使用

郭志
2023-03-14

我正在开发一个Spring应用程序,并在一个存储库上定义各种查找方法:

@Repository
public interface TicketRepository extends JpaRepository<TicketEntity, Long> {

List<TicketEntity> findByTicketId(@Param("ticketId") Long ticketId);

List<TicketEntity> findByTicketIdAndState(@Param("ticketId") Long ticketId, @Param("state") String state);

List<TicketEntity> findByTicketIdAndStateAndFlagged(@Param("ticketId") Long ticketId, @Param("state") String state, @Param("flagged") String Flagged);

}

问题是我有30列,可以选择对其进行筛选。这将导致存储库方法变得笨拙:

List<TicketEntity> findByTicketIdAndStateAndFlaggedAndCol4AndCol5AndCol6AndCol7AndCol8AndCol9AndCol10AndCol11AndCol12AndCol13AndCol14AndCol15AndCol16AndCol17AndCol18AndCol19AndCol120....);

JPA层应该如何设计以适应这种情况?

如果我创建一个具有属性的对象:

public class SearchObject {
   private String attribute1; 
   //Getter and Setters
.
.
.
.
}

我可以将<code>SearchObject</code>传递到一个查找方法中,Spring JPA将根据哪些属性为空来确定要插入哪些属性和用于哪些属性的语句-如果属性不为空,则为该属性生成相应的语句。

共有2个答案

吕树
2023-03-14

使用Spring Data JPA规范

细节解决方案:耐心等待

首先,创建一个SpecificationCriteria类来定义您的准则。这意味着将列过滤为键,将值过滤为值

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class SpecificationCriteria {
  private String key;
  private Object value;
}

然后创建规范标准构建器以构建您的标准

@Service
public class SpecificationCriteriaBuilder {

  public List<SpecificationCriteria> buildCriterias(String name) {
    List<SpecificationCriteria> specificationCriterias = new ArrayList<SpecificationCriteria>();
    if (!StringUtils.isEmpty(name)) {
      specificationCriterias
          .add(SpecificationCriteria.builder().key("name")
              .value(name).build());
    }
    // Here you can add other filter one by one 
    return specificationCriterias;
  }
}

然后创建一个SpecificationBuilder类来构建您的规范。您可以从过滤器选项(标准)列表构建到规范列表

import java.util.List;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

@Service
public class SpecificationBuilder<T> {

  public Specification<T> buildSpecification(List<SpecificationCriteria> specificationCriterias) {
    if (ObjectUtils.isEmpty(specificationCriterias)) {
      return null;
    }
    Specification<T> specification = getSpecification(specificationCriterias.get(0));
    for (int index = 1; index < specificationCriterias.size(); index++) {
      SpecificationCriteria specificationCriteria = specificationCriterias.get(index);
      specification =
          Specification.where(specification).and(getSpecification(specificationCriteria));
    }
    return specification;
  }

  public Specification<T> getSpecification(SpecificationCriteria specificationCriteria) {
    Specification<T> specification = new Specification<T>() {
      private static final long serialVersionUID = 2089704018494438143L;
      @Override
      public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
        return builder.equal(root.get(specificationCriteria.getKey()),
            specificationCriteria.getValue());
      }
    };
    return specification;
  }
}

在服务中首先构建标准,然后使用它们构建规范。然后在存储库调用中使用规范

@Service
@Transactional
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class UserService {

private final SpecificationCriteriaBuilder criteriaBuilder;
private final SpecificationBuilder<User> specificationBuilder;
private final UserRepository userRepository;

public List<User> getAll(String name) {
    List<SpecificationCriteria> specificationCriterias =
        criteriaBuilder.buildCriterias(name); // here you can pass other parameter as function argument 
    Specification<User> specification =
        specificationBuilder.buildSpecification(specificationCriterias);
    List<User> users = userRepository.findAll(specification);// pass the specifications
    return users;
  }

存储库扩展JpaSpecificationExecutor

@Repository
public interface UserRepository extends JpaRepository<User, Integer>, JpaSpecificationExecutor<User> {

}
闻华容
2023-03-14
  1. 创建将包含所有可选列的过滤器对象,例如:

@AllArgsConstructor公共类TicketFilter{

private final String col1;
private final Integer col2;

public Optional<String> getCol1() {
    return Optional.ofNullable(col1);
}

public Optional<Integer> getCol2() {
    return Optional.ofNullable(col2);
}

}

创建规范类:

公共类票证规范实现规范 {

private final TicketFilter ticketFilter;

public TicketSpecification(TicketFilter ticketFilter) {
    this.ticketFilter = ticketFilter;
}

@Override
public Predicate toPredicate(Root<Ticket> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
    List<Predicate> predicates = new ArrayList<>();
    ticketFilter.getTitle().ifPresent(col1 -> predicates.add(getCol1Predicate(root, col1)));
    ticketFilter.getDescription().ifPresent(col2 -> predicates.add(getCol2Predicate(root, col2)));
    return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
}

私有谓词getCol1Predicate(根,根,字符串标题){return Root.get(“col1”).in(col1);}

}

使用您的存储库:ticketRepository.findAll(规范);

 类似资料:
  • 问题内容: 我正在使用Hibernate Validator 4.0.2,Spring 3.0和Hibernate 3.3.2(据我所知,是JPA2之前的版本)作为JPA 1提供程序。 我发现将Validator集成到MVC层很容易(这是可行的),但是看不到如何将验证器自动集成到JPA entityManager(JPA 1)中。 基本上,我有一些实体将保留下来,但它们不是来自Web层,因此尚未经

  • 这很有魅力: 但如果我想按多个单词搜索,它将不返回任何内容,例如: 当我使用CURL时,我通过将添加到我的JSON属性来解决这个问题: 卷曲-XGET“http://localhost:9200/_search“-d”{“查询”:{“匹配”:{“字段”:{“查询”:“word\u 1 word\u 2”,““模糊性”:“自动”,““运算符”:“和”}}}}}” 我如何在Java中实现这一点?

  • 问题内容: 我想在Monoose中将两个OR查询与AND结合在一起,例如以下SQL语句: 我在NodeJS模块中尝试了此操作,该模块仅从主应用程序获取模型对象: 但这是行不通的,所有OR条件都将像下面的SQL语句一样连接在一起: 如何在猫鼬中结合AND 和AND 的两个条件? 问题答案: 直接按以下方式创建查询对象可能是最简单的: 但是,您也可以使用最新的3.x Mongoose版本中提供的帮助程

  • 本文向大家介绍我们可以结合使用MySQL IN AND LIKE运算符吗?,包括了我们可以结合使用MySQL IN AND LIKE运算符吗?的使用技巧和注意事项,需要的朋友参考一下 是的,我们可以使用LIKE和OR运算符在MySQL中组合IN和LIKE运算符。让我们首先创建一个表- 使用插入命令在表中插入一些记录- 使用select语句显示表中的所有记录- 输出结果 这将产生以下输出- 以下是在

  • 我们有一个现有的谓词来从表中获取数据,我们还需要将此条件添加到该查询中 我们尝试了不同的方法,但我们所能做到的就是 简单括号应在<代码>或 之后开始,并应在最终条件之后结束。 我们试过这些 步骤-1 步骤-2 我们能得到一些帮助吗?

  • 问题内容: 给定此选择器: 它将匹配一个正文,该正文的类包含 page-node-add- 的子字符串,而类恰好是 page-node-edit 我想说匹配第一个或第二个(但不能同时匹配)。可能吗? 使用逗号的问题: 如果我有一个长选择器,例如: 我原本以为CSS3可以解决这个问题,但是我想到的是: 谢谢 问题答案: 您需要使用逗号将它们分开: 使用逗号的问题: …是除了逗号以外,您无法做其他任何