【问题标题】:How to mimic List<Optional<T>> like behaviour in Spring Data Repo?如何在 Spring Data Repo 中模仿 List<Optional<T>> 之类的行为?
【发布时间】:2019-01-16 10:55:27
【问题描述】:

我正在尝试使用list of Id's query 数据库,如果它们不存在,请对它们做一些事情。

我的计划是做类似的事情

List<Optional<MyObject>> fingById(Set<String> myIds);

我知道这不会开箱即用,因为我认为即使所有 id 都存在,也无法保证它们会被订购,所以如果其中一些存在,我会得到一些随机的 null 选项将无法使用返回它的 ID。

基本上我最终需要做的是检索这些对象,更新一个字段或使用默认值(如果不存在)创建它们。

批量执行此操作的最佳方法是什么?

谢谢:)

【问题讨论】:

  • 为什么要有List&lt;Optional&lt;MyObject&gt;&gt;?如果您想要每个String ID 的MyObjectMap&lt;String,MyObject&gt; 不是更好吗?

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


【解决方案1】:

您可以通过他们的 id 将结果映射到Map&lt;String, Optional&lt;MyObject&gt;&gt;,然后用Optional.empty() 填写空白。

List<MyObject> findByIdIn(Set<String> ids);

default Map<String, Optional<MyObject>> mapByIdIn(Set<String> ids) {
    Map<String, Optional<MyObject>> found = findByIdIn(ids)
            .stream()
            .collect(Collectors.toMap(MyObject::getId, Optional::of));
    ids.stream()
       .filter(id -> !found.containsKey(id))
       .forEach(id -> found.put(id, Optional.empty()));
    return found;
}

【讨论】:

  • 我真的很喜欢这个,而且我实际上了解了这个我还没有见过的默认方法的东西。谢谢!
  • 顺便说一句,刚刚尝试了您的选择,遗憾的是:Servlet.service() for servlet [dispatcherServlet] in context with path [/sacs] throw exception [Request processing failed;嵌套异常是 org.springframework.dao.InvalidDataAccessResourceUsageException: could not extract ResultSet; SQL [不适用];嵌套异常是 org.hibernate.exception.SQLGrammarException: could not extract ResultSet] with root cause java.sql.SQLSyntaxErrorException: ORA-01797: this operator must be after aNY or ALL
  • @epsilnmajorquezero 尝试重命名为findByIdIn
  • 哇,好快,正好有时间自己找:)再次感谢!
【解决方案2】:

我认为使用 ListOptional 值不是一个好主意。相反,我建议只使用存储库的默认方法并查询所有现有实体。

List<MyObject> findAll();

之后,您可以遍历所有对象并检查缺少的 id。为了提高性能,我建议使用Map

var objectMap = repository.findAll().stream()
    .collect(Collectors.toMap(MyObject::getId, Function::Identity);

然后,您可以简单地检查地图中是否包含任何 id:

myIds.stream().filter(objectMap::contains)
    .forEach({
        // do some stuff, present id
    });

myIds.stream().filter((id) -> !myMap.contains(id))
    .forEach({
        // do some stuff, not present id
    });

【讨论】:

  • findAll() 可能会从几十万到几百万个条目中检索,而我实际上只需要检索大约 100 个 Id,所以我会说这将是一个相当大的过度 :)
  • @epsilnmajorquezero 同意,然后findAll 不起作用。
  • 但是,如果您使用 Spring 数据存储库,您仍然可以使用 List&lt;MyObject&gt; findAllByIdIn(List&lt;String&gt; ids)
  • 是的,但这意味着“手动”检查丢失的那些,我想知道如果可能的话,有一种方法可以同时做这两件事。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-05-29
  • 1970-01-01
  • 2016-02-29
  • 2021-10-02
  • 1970-01-01
  • 1970-01-01
  • 2018-08-25
相关资源
最近更新 更多