【问题标题】:How to build dynamic queries with Spring Data Redis Repositories?如何使用 Spring Data Redis Repositories 构建动态查询?
【发布时间】:2017-07-20 00:33:18
【问题描述】:

我正在使用这样的存储库使用 spring-data-redis 测试 Redis:

public interface CreditCardRepository extends CrudRepository<CreditCard, String>{
    List<CreditCard> findByIssuer(String issuer);
    List<CreditCard> findByCreditNetwork(String creditNetwork);
    List<CreditCard> findByCreditNetworkAndIssuer(String creditNetwork, String issuer);
}

以上方法将查询 Redis 结构,例如:

creditcard:creditNetwork:mastercard
creditcard:creditNetwork:visa
creditcard:issuer:company1
creditcard:issuer:company2

现在我的 CreditCard 对象包含两个属性(issuer、network 和 id),所以很容易像这样搜索对象:

private List<CreditCard> searchCardFromCache(CreditCardGetReq req) {
    if (req.getIssuer() != null && req.getNetwork() != null) { 
        return ccRepository.findByIssuerAndCreditNetwork(req.getIssuer(), req.getNetwork().name()); 
    }
    if (req.getIssuer() != null) { 
        return ccRepository.findByIssuer(req.getIssuer()); 
    }
    if (req.getNetwork() != null) { 
        return ccRepository.findByCreditNetwork(req.getNetwork().name()); 
    }
    return null;
}

但是,我不喜欢这段代码,因为我必须创建所有属性的组合并且会非常混乱。未来,我计划拥有 15 个属性,因此“if”链是不可能的。

想问一下如何使用spring-data-redis创建动态查询,这样Redis可以比检查每个属性更好的方式根据对象属性返回交集?

已尝试通过硬编码(我之前从存储库 findByIssuerAndCreditNetwork 中删除)使用 MethodHandle,该方法名称将像这样动态生成:

MethodType methodType = MethodType.methodType(cardList.getClass(), String.class, String.class);
// Dynamic create 'findByIssuerAndCreditNetwork'
MethodHandle methodHandle = MethodHandles.lookup().findVirtual(CreditCardRepository.class, "findByIssuerAndCreditNetwork", methodType);

但似乎 MethodHandle 不起作用,因为我收到以下错误:

java.lang.NoSuchMethodException:没有这样的方法:com.creditcard.dao.CreditCardRepository.findByIssuerAndCreditNetwork(String,String)ArrayList/invokeInterface

【问题讨论】:

  • 有趣的问题。由于您正在定义调用什么方法的实际规则,因此您仍然需要遍历 CreditCardGetReq 的所有属性
  • @Eugene,是的,我不在乎遍历所有属性是容易的部分,但是执行 findByX 组合是一个挑战。我会尝试构建一个动态字符串,例如“findByXAndY”动态并通过反射调用 repo 是否可以解决问题,但我觉得我在这里遗漏了一些东西
  • 实际上我也在考虑这个方向......但是通过MethodHandles,而不是反射,如果你有存储库的实际实例,这将起作用。问题是方法句柄显然需要它们的调用参数
  • @Eugene,已经尝试过 MethodHandle 但似乎它不起作用。也用这些细节更新了问题
  • 我自己没有用过这个,但是RedisCallbackRedisTemplate不会给你你想要的吗?虽然使用纯 Spring Data 会更抽象

标签: java spring redis spring-data spring-data-redis


【解决方案1】:

目前,不支持创建动态查询。听起来好像Query by Example 可能是您正在寻找的东西。 Spring Data MongoDB 和 Spring Data JPA 已经实现了 Query by Example。

数据存储模块创建查询以匹配示例域对象:

Person person = new Person();                         
person.setFirstname("Dave");                          

Example<Person> example = Example.of(person); 

MongoRepository repo = …
List<Person> result = repo.findAll(example); // returns all objects that with Dave in firstname

Spring Data Redis 目前不支持通过示例查询,但应该可以提供基本支持。

我创建了一张票 DATAREDIS-605 来跟踪此功能的进度。

【讨论】:

  • 谢谢马克,拥有这个功能肯定很棒。我将自己添加为 Jira 的观察者。
  • 马克,当这个功能发布时,如果你想提供 spring-data-redis 版本和具体示例,我可以将这个答案标记为已接受,以便社区知道如何使用它。
  • 马克,我在 Jira 工单中注意到您已经通过示例完成了查询的开发。这已经可用了吗?你提供的代码和spring data redis一起使用是一样的吗?如果是,请让我知道接受答案,如果不是,您可以提供示例代码吗?非常感谢
  • 它在 2.1 版本的快照版本中可用。试一试,很高兴收到早期反馈。
  • 你能根据发布的功能更新这个答案吗?
猜你喜欢
  • 2018-11-25
  • 2014-08-25
  • 2022-08-14
  • 2016-01-08
  • 2019-05-20
  • 1970-01-01
  • 1970-01-01
  • 2013-08-09
  • 2015-02-07
相关资源
最近更新 更多