首页 文章

Spring数据JPA Repository Match All Columns或整个pojo

提问于
浏览
2

我试图搜索但没有找到准确的解决方案 . 我有 Address 实体 . 对于每个新的Address请求,首先我要检查数据库中是否存在相同的地址请求 . 我的申请是针对仓库的,并且有可能多次同一地址请求 .

Address Entity

@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 .

EDIT

根据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的第5步)

2 回答

  • 3

    您正在寻找的是 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 extends ExtendedJpaRepository .

  • 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
          }
        };
      }
    }
    

    您在业务需求抽象级别上表达了一些标准并创建了可执行规范 . 因此客户端可能使用如下规范:List customers = 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

相关问题