【问题标题】:crudrepository findBy method signature for list of tuples元组列表的 crudrepository findBy 方法签名
【发布时间】:2018-06-10 12:05:00
【问题描述】:

我有一个这样的实体类:

@Entity
@Table(name = "CUSTOMER")
class Customer{
    @Id
    @Column(name = "Id")
    Long id;
    @Column(name = "EMAIL_ID")
    String emailId;
    @Column(name = "MOBILE")
    String mobile;
}

如何使用 crudrepository spring data jpa 为以下查询编写 findBy 方法?

select * from customer where (email, mobile) IN (("a@b.c","8971"), ("e@f.g", "8888"))

我期待类似的东西

List<Customer> findByEmailMobileIn(List<Tuple> tuples);

我想从给定对中获取客户列表

【问题讨论】:

  • 我认为你只能这样做List&lt;Customer&gt; findByEmailInAndMobileIn(List&lt;String&gt; emails, List&lt;String&gt; mobiles);
  • 这很可悲。你认为我应该在这个用例中使用 spring jdbctemplate 吗?
  • 这并不难过,这就是 spring-data 的构建方式。您正在给它一个自定义对象,弹簧数据无法弄清楚您的意思。我不确定使用 @Query 注释并指定您想要的 sql 语句是否适用于您的 Tuple 类。您必须检查一下。

标签: java spring collections tuples spring-data-jpa


【解决方案1】:

我认为这可以通过org.springframework.data.jpa.domain.Specification 完成。您可以传递您的元组列表并以这种方式处理它们(不要关心 Tuple 不是实体,但您需要定义此类):

public class CustomerSpecification implements Specification<Customer> {

    // names of the fields in your Customer entity
    private static final String CONST_EMAIL_ID = "emailId";
    private static final String CONST_MOBILE = "mobile";

    private List<MyTuple> tuples;

    public ClaimSpecification(List<MyTuple> tuples) {
        this.tuples = tuples;
    }

    @Override
    public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
        // will be connected with logical OR
        List<Predicate> predicates = new ArrayList<>();

        tuples.forEach(tuple -> {
            List<Predicate> innerPredicates = new ArrayList<>();
            if (tuple.getEmail() != null) {
                 innerPredicates.add(cb.equal(root
                     .<String>get(CONST_EMAIL_ID), tuple.getEmail()));
            }
            if (tuple.getMobile() != null) {
                 innerPredicates.add(cb.equal(root
                     .<String>get(CONST_MOBILE), tuple.getMobile()));
            }
            // these predicates match a tuple, hence joined with AND
            predicates.add(andTogether(innerPredicates, cb));
        });

        return orTogether(predicates, cb);
    }

    private Predicate orTogether(List<Predicate> predicates, CriteriaBuilder cb) {
        return cb.or(predicates.toArray(new Predicate[0]));
    }

    private Predicate andTogether(List<Predicate> predicates, CriteriaBuilder cb) {
        return cb.and(predicates.toArray(new Predicate[0]));
    }
}

你的仓库应该扩展接口JpaSpecificationExecutor&lt;Customer&gt;

然后用元组列表构造一个规范并将其传递给方法customerRepo.findAll(Specification&lt;Customer&gt;) - 它返回一个客户列表。

【讨论】:

  • 这正是我过去 5-6 小时一直在寻找的。太棒了!
【解决方案2】:

使用投影可能更干净:

@Entity
@Table(name = "CUSTOMER")
class CustomerQueryData {
    @Id
    @Column(name = "Id")
    Long id;
    @OneToOne
    @JoinColumns(@JoinColumn(name = "emailId"), @JoinColumn(name = "mobile"))
    Contact contact;
}

联系实体:

@Entity
@Table(name = "CUSTOMER")
class Contact{
    @Column(name = "EMAIL_ID")
    String emailId;
    @Column(name = "MOBILE")
    String mobile;
}

指定实体后,repo:

CustomerJpaProjection extends Repository<CustomerQueryData, Long>, QueryDslPredicateExecutor<CustomerQueryData> {
    @Override
    List<CustomerQueryData> findAll(Predicate predicate);
 }

还有回购电话:

ArrayList<Contact> contacts = new ArrayList<>();
contacts.add(new Contact("a@b.c","8971"));
contacts.add(new Contact("e@f.g", "8888"));
customerJpaProjection.findAll(QCustomerQueryData.customerQueryData.contact.in(contacts));

未经测试的代码。

【讨论】:

  • 不明白为什么 QueryDslPredicateExecutor 没有得到更多的爱。这使得一个非常棘手的用例成为可能。感谢分享!
猜你喜欢
  • 2015-12-24
  • 2019-01-06
  • 2018-06-02
  • 2018-01-07
  • 2015-05-01
  • 2018-01-07
  • 2020-03-09
  • 1970-01-01
相关资源
最近更新 更多