我在项目中使用 Spring Data GemFire ,并且正在使用存储库从缓存中获取查询结果,如此处所述:https://docs.spring.io/spring-gemfire/docs/1.3.3.RELEASE/reference/html/gemfire-repositories.html
下面是我的 Repository 接口:
@Repository
@Region("someRegion")
public interface SomeRegionRepository extends GemfireRepository<CustomObject, Object> {
//Below works when id exists in gemfire region.
//But when id does not exists it
//gives java.lang.IllegalStateException: Unsupported query
@Query("select a.num from /someRegion a where a.id = $1")
Integer getNumById(String id);
//Below returns CustomObject instance when id exists in gemfire region.
//But when id does not exists it returns null (Expected)
CustomObject findById(String id);
}
在OQL查询中找不到该键的数据时,有什么方法可以返回0或其他值?
或者,有什么方法可以获取null
值,以便在没有数据时可以在调用者代码中处理它?
在此处指定的OQL中有一个叫做NVL
的东西(如果第一个表达式为空,它可以返回其他值/表达式):但是我无法获得正确用法的语法。
请帮助。谢谢。
答案 0 :(得分:1)
首先,在我们开始之前有一个保管物品...
我发现您在上面的GemFire文档参考中引用了 Pivotal GemFire 9.7
,但随后引用了Spring Data GemFire (SDG)1.3.3.RELEASE
参考文档。我当然希望您不要将SDG 1.3.3.RELEASE
与Pivotal GemFire 9.7
一起使用。基于Pivotal GemFire 7.0.1的SDG 1.3.3已经过时了,不再受支持。
我怀疑您没有使用SDG 1.3.x
,因此您应该始终参考最新的文档,here,特别是here。甚至Google Search都可以显示最新文档。
此外,您可以参考 Pivotal GemFire的Spring数据 Version Compatibility Matrix,以获取更多详细信息。反正...
因此,我写了test class以更好地了解您的UC。
在测试中,我使用可查询的Person class为age
field/property建模。我有一个Person
类型的PersonRepository,并且我写了一个与上述示例非常相似的查询,以按年龄usual和{{3} }。
问题是,对于存储库,您想要通过返回null
或0
来防止结果缺失的愿望是模棱两可的。
对于1,如果您返回了多个结果(例如,如SELECT a.num FROM /SomeRegion a
;即没有谓词),并且结果没有排序,那么您将无法知道哪个值是{{1} },除非您还返回了结果集中的密钥。
当然,这里不是这种情况,您确实使用谓词(即null
)通过ID对查询进行了限定。但是,在这种情况下,在查看查询(即... WHERE a.id = $1
)时,不清楚给定ID(即键)是否没有结果,还是 num 是{ {1}}。你真的不知道。
我的测试继续说明这一点。
我有2个人SELECT a.num FROM ...
,null-safe。乔恩有明确的年龄,而简没有。当然,两个人都存在于缓存中(即“人”区域)。
当我查询乔恩并断言他的年龄时,我得到了here。
或者,当我查询Jane并声明她的年龄时,我可以获得null
或["Jon Doe", "Jane Doe"]
两个值中的一个,为expected result(当前为null
,因为我正在使用expected here)。如果我将查询更改为null-safe query,那么Jane的0
的返回值实际上将为0
,我可以这样声明。
但是,当我们开始查询一个不存在的人时,GemFire的行为显而易见。没有结果。我举例说明了这2种不同的方式(不使用存储库),直接使用GemFire的usual query,然后再次使用SDG的便捷QueryService
API,它简单地包装了GemFire查询API(这也是存储库的内幕;实际上,存储库添加的价值是映射/转换功能。
如您所见,对于GemfireTemplate
class,我必须处理没有结果的情况。
就存储库而言,因为您使用了自定义查询,所以对于存储库基础结构而言,这不是立即显而易见的,哪一部分(即查询的中间结果)是age
。
如果您有null
怎么办?
是人null
,地址SELECT person.address.city.name FROM ...
还是城市null
?应该如何统一处理?该人可能会退出,但地址可能是null
,这可能与人或城市为null
时的行为有所不同。
实际上,存储库抽象确实处理null
返回值,如example所示。
那么,我们从这里去哪里?
我们有几种选择:
您可以执行,here首先...
返回personRepository.existsById(bobDoe.getName()) ? personRepository.getAge(bobDoe.getName()) :0;
您可以在DAO的 Repository 之外处理此问题(也许改编/修饰 Repository 并委派用于简单查询情况,而不是用于复杂查询的情况)涉及使用null
注释,应谨慎使用)。
@存储库 类PersonDao {
null
}
还是
另一种选择是让我们在SD中提供额外的支持,类似于...
@Query
或者也许...
@Autowired
private PersonRepository personRepository;
Person findById(String name) {
return this.personRepository.findById(name).orElse(null);
}
Integer getAge(String name) {
// Either use the approach in #1, or do https://github.com/jxblum/contacts-application/blob/master/tests-example/src/test/java/example/tests/spring/data/gemfire/NullValueReturningRepositoryQueryMethodIntegrationTests.java#L143-L151.
}
...
仍然这种方法不能解决歧义性问题,需要更多的思考。
真正的好处是,如果OQL处理Elvis运算符,就像(在我上面更复杂的示例中)...
选择个人?。地址?.city?.name从/人...
无论如何,我希望这能给您一些想法。在继续前进之前,我需要更多地思考上面的#3。
如果您还有其他问题/反馈/想法,请在评论中提供它们,或者随时提出existence check。
谢谢!