使用联合表上的规范和CriteriaQuery的Spring JPA [英] Spring JPA using Specifications and CriteriaQuery on Joint Tables

查看:133
本文介绍了使用联合表上的规范和CriteriaQuery的Spring JPA的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用JPA规范和CriteriaQuery以便将where子句添加到我的实体中.

I am using JPA specifications and CriteriaQuery in order to add where clauses to my entities..

域类:

public class Domain {

  @Id
  @Column(name = "id")
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Long id;

  @Column(name = "account_id")
  private Long accountId;

  @OneToMany(cascade = CascadeType.ALL)
  @JoinColumn(name = "domain_id")
  private List<Notification> notification;
}

通知类别:

public class Notification {

  @Id
  @Column(name = "id")
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Long id;

  @Column(name = "domain_id")
  private Long domainId;

  @Column(name = "contact")
  private String contact;
}

然后我将使用以下类来创建规范":

Then I have the following class which I use to create Specifications:

public class DomainSpecification implements Specification<Domain> {

  final private SearchCriteria criteria;

  public DomainSpecification(SearchCriteria searchCriteria) {
    this.criteria = searchCriteria;
  }

  @Override
  public Predicate toPredicate(
          Root<Domain> root, CriteriaQuery<?> query, CriteriaBuilder builder) {

     switch (criteria.getOperation()) {
      case ":":
        if (root.get(criteria.getKey()).getJavaType() == String.class) {
          return builder.like(
                  root.<String>get(criteria.getKey()),
                  "%" + criteria.getValue() + "%");
        } else {
          return builder.equal(root.get(criteria.getKey()),
                  criteria.getValue());
        }
      case "=":
        return builder.equal(root.get(criteria.getKey()),
                criteria.getValue());
      default:
        return null;
    }
  }

}

和SearchCriteria对象:

And the SearchCriteria Object:

public class SearchCriteria {

  private final String key;
  private final String operation;
  private final Object value;

  public SearchCriteria(String key, String operation, Object value) {
    this.key = key;
    this.operation = operation;
    this.value = value;
  }

  public String getKey() {
    return key;
  }

  public String getOperation() {
    return operation;
  }

  public Object getValue() {
    return value;
  }

}

然后,每当我要创建where子句时,我都会执行以下操作:

Then, whenever I want to create a where clause, I do the following:

DomainSpecification idSpecification
        = new DomainSpecification(
                new SearchCriteria("id", "=", domainId));

Specifications<Domain> specifications = Specifications.where(idSpecification);

final Domain domain = this.domainRepository.findOne(specifications);

这将通过域实体中名为id的字段进行搜索.

This would search by the field called id in the Domain Entity..

现在,我如何也可以按加入的实体进行过滤?例如,我要过滤Domain.id = 10和Notification.contact ="abc"的位置?

Now, how can I also filter by the entity that I am joining with ? For example, I want to filter where Domain.id = 10 and Notification.contact = "abc"?

感谢您的帮助

推荐答案

您可以将Specification的定义包装到帮助程序类中:

You could wrap your Specifications definitions into helper class:

public class DelegationSpecificationsHelper {

    public static Specification<Domain> notificationContactSpec(String contact) {
        return (root, query, cb) -> cb.equal(root.join("notification").get("contact"), contact);
    }

    public static Specification<Domain> idSpec(SearchCriteria searchCriteria) {
        switch (criteria.getOperation()) {
          case ":":
            if (root.get(criteria.getKey()).getJavaType() == String.class) {
              return builder.like(
                      root.<String>get(criteria.getKey()),
                      "%" + criteria.getValue() + "%");
            } else {
              return builder.equal(root.get(criteria.getKey()),
                      criteria.getValue());
            }
          case "=":
            return builder.equal(root.get(criteria.getKey()),
                    criteria.getValue());
          default:
            return null;
        }
    }
}

然后您可以像这样使用它:

And then you could use it like this:

Specifications<Domain> specifications = Specifications.where(DelegationSpecificationsHelper.idSpec(new SearchCriteria("id", "=", domainId))
                                                      .and(DelegationSpecificationsHelper.notificationContactSpec("someSearchString"));

静态导入和一些重构之后:

After static imports and some refactoring:

SearchCriteria idCriteria = new SearchCriteria("id", "=", domainId)
Specifications<Domain> specifications = 
                 Specifications.where(idSpec(idCriteria)
                               .and(notificationContactSpec("someSearchString"));

当然,您应该从这里摆脱硬编码的值: cb.equal(root.join("notification").get("contact"), contact);并使用一些DTO对象或生成的JPA元模型代替.

Of course you should get rid of hardcoded values from here: cb.equal(root.join("notification").get("contact"), contact); and use some DTO object or generated JPA meta model instead.

添加元模型后,它看起来可能像这样:

After adding metamodel it could look like this:

 public static Specification<Domain> notificationContactSpec(String contactValue) {
        return (root, query, cb) -> cb.equal(root.join(Domain_.notification).get(Notification_.contact), contactValue);
 }

有关元模型生成的更多信息: https://docs.jboss.org/hibernate/orm /5.0/topical/html/metamodelgen/MetamodelGenerator.html

More about metamodel generation: https://docs.jboss.org/hibernate/orm/5.0/topical/html/metamodelgen/MetamodelGenerator.html

这篇关于使用联合表上的规范和CriteriaQuery的Spring JPA的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆