【问题标题】:Spring data JPA Repository Match All Columns or whole pojoSpring data JPA Repository 匹配所有列或整个 pojo
【发布时间】:2015-04-06 05:37:28
【问题描述】:

我尝试搜索但没有找到准确的解决方案。我有Address 实体。对于每个新的地址请求,首先我想检查数据库中是否存在相同的地址。我的申请是针对仓库的,同样的地址请求可能会多次出现。

地址实体

@Entity
@NamedQuery(name="Address.findAll", query="SELECT a FROM Address a")
public class Address implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Integer id;

    private String firstname;

    private String lastname;

    private String address1;

    private String address2;

    private String address3;

    private String city;

    private String postcode;

    @JsonProperty(value="county")
    private String state;

    private String country;

    private String telephoneno;

    private String mobileno;    

    private String email;

    //bi-directional many-to-one association to Collection
    @OneToMany(mappedBy="address")
    @JsonIgnore
    private List<Collection> collections;

    //bi-directional many-to-one association to Delivery
    @OneToMany(mappedBy="address")
    @JsonIgnore
    private List<Delivery> deliveries;


    public Address() {
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getAddress1() {
        return this.address1;
    }

    public void setAddress1(String address1) {
        this.address1 = address1;
    }

    public String getAddress2() {
        return this.address2;
    }

    public void setAddress2(String address2) {
        this.address2 = address2;
    }

    public String getAddress3() {
        return this.address3;
    }

    public void setAddress3(String address3) {
        this.address3 = address3;
    }

    public String getCity() {
        return this.city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public String getCountry() {
        return this.country;
    }

    public void setCountry(String country) {
        this.country = country;
    }

    public String getEmail() {
        return this.email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getPostcode() {
        return this.postcode;
    }

    public void setPostcode(String postcode) {
        this.postcode = postcode;
    }

    public String getState() {
        return this.state;
    }

    public void setState(String state) {
        this.state = state;
    }

    public String getFirstname() {
        return firstname;
    }

    public void setFirstname(String firstname) {
        this.firstname = firstname;
    }

    public String getLastname() {
        return lastname;
    }

    public void setLastname(String lastname) {
        this.lastname = lastname;
    }

    public String getTelephoneno() {
        return telephoneno;
    }

    public void setTelephoneno(String telephoneno) {
        this.telephoneno = telephoneno;
    }

    public String getMobileno() {
        return mobileno;
    }

    public void setMobileno(String mobileno) {
        this.mobileno = mobileno;
    }

    public List<Collection> getCollections() {
        return this.collections;
    }

    public void setCollections(List<Collection> collections) {
        this.collections = collections;
    }

    public Collection addCollection(Collection collection) {
        getCollections().add(collection);
        collection.setAddress(this);

        return collection;
    }

    public Collection removeCollection(Collection collection) {
        getCollections().remove(collection);
        collection.setAddress(null);

        return collection;
    }

    public List<Delivery> getDeliveries() {
        return this.deliveries;
    }

    public void setDeliveries(List<Delivery> deliveries) {
        this.deliveries = deliveries;
    }

    public Delivery addDelivery(Delivery delivery) {
        getDeliveries().add(delivery);
        delivery.setAddress(this);

        return delivery;
    }

    public Delivery removeDelivery(Delivery delivery) {
        getDeliveries().remove(delivery);
        delivery.setAddress(null);

        return delivery;
    }


}

我知道一种解决方案可能是在存储库中声明一个方法,其中 And 包括所有字段。例如

public Address findByFirstnameAndLastnameAndAddress1AndAddress2AndAddress3AndCityAndPostcode....();

但我想知道是否有更好的方法来做到这一点。有什么东西可以让我通过新的Address 对象来检查数据库中是否存在相同的Address

编辑

根据 Manish 的回答,我的理解如下:

1> 如答案中所述创建接口ExtendedJpaRepository

2> 为这个接口创建实现类如下(参考:Spring Data Jpa Doc

public class MyRepositoryImpl<T, ID extends Serializable>
  extends SimpleJpaRepository<T, ID> implements MyRepository<T, ID> {
        List<T> findByExample(T example){
            //EclipseLink implementation for QueryByExample
        }
  }

3> 然后对于每个存储库接口,扩展ExtendedJpaRepository。这应该使 findByExample 在每个存储库中随时可用。

4> 创建自定义存储库工厂以替换 Spring data JPA doc 的步骤 4 中所述的默认 RepositoryFactoryBean。

5> 声明自定义工厂的bean。(Spring Data JPA Doc 的Step-5)

【问题讨论】:

  • 你有没有试过findByAddress(Address address)在我的项目中工作
  • 是的,我试过了。但是在启动tomcat时给了我一个错误,指出“在地址实体中找不到地址”。 Tomcat 尝试为 AddressDataRepository & 创建对象,此时它会抛出错误。你的代码是如何工作的?您是否在 `Address pojo 中创建了 Address 变量?
  • 好的,我再看看。对不起,我的记忆是危险的。我有点搞混了。在地址上和你一样,findBy..Attributes...

标签: java spring spring-mvc jpa spring-data-jpa


【解决方案1】:

您要查找的内容称为Query-by-Example。正如this post 中所解释的,此功能被考虑用于 JPA 2.0,但未包含在最终版本中。该帖子还解释说,大多数 JPA 提供程序都具有实现此功能所需的功能。

您可以创建开箱即用地提供此功能的自定义 JPA 存储库实现。详情请见Spring Data JPA documentation

一个起点是创建一个新界面,例如:

public interface ExtendedJpaRepository<T, ID extends Serializable>
    extends JpaRepository<T, ID> {
  List<T> findByExample(T example);
}

然后,为此接口插入一个使用底层 JPA 提供程序的实现。最后,配置您的自定义实现以用于所有存储库接口。

之后,您应该可以调用addressRepository.findByExample(address),前提是AddressRepository 扩展ExtendedJpaRepository

【讨论】:

  • 你说这个 - "Then, plug in an implementation for this interface that uses your underlying JPA provider. Finally, configure your custom implementation to be used for all your repository interfaces." 我将如何使用 MySql 为 eclipseLink 实现这一点?
  • findByExample 的实现是特定于提供商的。 This post 展示了如何使用一些常见的 JPA 提供程序(包括 EclipseLink)来做到这一点。 JPA 独立于数据库,因此您不必担心 MySQL。
  • 好的。我已经在上面问题的EDIT 部分写下了我理解的内容。如果我理解正确,请告诉我。
  • Here 是一个示例工作应用程序。
【解决方案2】:

您可以使用 Spring-data 开箱即用的规范。并能够使用标准 API 以编程方式构建查询。要支持规范,您可以使用 JpaSpecificationExecutor 接口扩展存储库接口

public interface CustomerRepository extends SimpleJpaRepository<T, ID>, JpaSpecificationExecutor {

}

附加接口 (JpaSpecificationExecutor ) 带有允许您以多种方式执行规范的方法。

例如 findAll 方法将返回所有符合规范的实体:

List<T> findAll(Specification<T> spec);

规范界面如下:

public interface Specification<T> {
  Predicate toPredicate(Root<T> root, CriteriaQuery<?> query,
            CriteriaBuilder builder);
}

好的,那么典型的用例是什么?规范可以很容易地用于在实体之上构建一组可扩展的谓词,然后可以将其与 JpaRepository 组合并使用,而无需为每个需要的组合声明查询(方法)。这是一个例子: 例 2.15。客户规格

public class CustomerSpecs {

  public static Specification<Customer> isLongTermCustomer() {
    return new Specification<Customer>() {
      public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> query,
            CriteriaBuilder builder) {

         LocalDate date = new LocalDate().minusYears(2);
         return builder.lessThan(root.get('dateField'), date);
      }
    };
  }

  public static Specification<Customer> hasSalesOfMoreThan(MontaryAmount value) {
    return new Specification<Customer>() {
      public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query,
            CriteriaBuilder builder) {

         // build query here
      }
    };
  }
}

您在业务需求抽象级别上表达了一些标准并创建了可执行的规范。因此,客户可能会使用如下规范: 列出客户 = customerRepository.findAll(isLongTermCustomer());

您还可以结合规范 例 2.17。组合规格

MonetaryAmount amount = new MonetaryAmount(200.0, Currencies.DOLLAR);
List<Customer> customers = customerRepository.findAll(
  where(isLongTermCustomer()).or(hasSalesOfMoreThan(amount)));

如您所见,规范提供了一些粘合代码方法来链接 并结合规格。因此扩展您的数据访问层是 只需创建新的规范实现和 将它们与现有的结合起来。

您可以创建复杂的规范,这是一个示例

public class WorkInProgressSpecification {

    public static Specification<WorkInProgress> findByCriteria(final SearchCriteria searchCriteria){

        return new Specification<WorkInProgress>() {

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

                List<Predicate> predicates = new ArrayList<Predicate>();

                if(searchCriteria.getView()!=null && !searchCriteria.getView().isEmpty()){
                    predicates.add(cb.equal(root.get("viewType"), searchCriteria.getView()));
                }if(searchCriteria.getFeature()!=null && !searchCriteria.getFeature().isEmpty()){
                    predicates.add(cb.equal(root.get("title"), searchCriteria.getFeature()));
                }if(searchCriteria.getEpic()!=null && !searchCriteria.getEpic().isEmpty()){
                    predicates.add(cb.equal(root.get("epic"), searchCriteria.getEpic()));
                }if( searchCriteria.getPerformingGroup()!=null && !searchCriteria.getPerformingGroup().isEmpty()){
                    predicates.add(cb.equal(root.get("performingGroup"), searchCriteria.getPerformingGroup()));
                }if(searchCriteria.getPlannedStartDate()!=null){
                        System.out.println("searchCriteria.getPlannedStartDate():" + searchCriteria.getPlannedStartDate());
                    predicates.add(cb.greaterThanOrEqualTo(root.<Date>get("plndStartDate"), searchCriteria.getPlannedStartDate()));
                }if(searchCriteria.getPlannedCompletionDate()!=null){
                    predicates.add(cb.lessThanOrEqualTo(root.<Date>get("plndComplDate"), searchCriteria.getPlannedCompletionDate()));
                }if(searchCriteria.getTeam()!=null && !searchCriteria.getTeam().isEmpty()){
                    predicates.add(cb.equal(root.get("agileTeam"), searchCriteria.getTeam()));
                }

                return cb.and(predicates.toArray(new Predicate[]{}));
            }
        };
    }
}

这里是JPA Respositories docs

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-08-31
    • 1970-01-01
    • 1970-01-01
    • 2021-06-26
    • 1970-01-01
    • 2021-12-22
    • 2020-10-30
    • 2012-12-06
    相关资源
    最近更新 更多