【问题标题】:spring-data-jdbc: query containing entity with a 1-n relationspring-data-jdbc:查询包含具有 1-n 关系的实体
【发布时间】:2020-03-21 20:58:49
【问题描述】:

如何为包含 1-n 引用的实体编写查询?

基于spring-data-jdbc 示例,我将通过以下单元测试对其进行解释:

@Test
public void customQuery_ReferenceMultipleInstances() {
  // prepare
  LegoSet smallCar = createLegoSet("Small Car 01", 5, 12);
  smallCar.setManual(new Manual("Just put all the pieces together in the right order", "Jens Schauder"));
  smallCar.addModel("suv", "SUV with sliding doors.");
  smallCar.addModel("roadster", "Slick red roadster.");
  repository.save(smallCar);

  // execute
  List<LegoSet> actual = repository.findByName("Small Car 01");
  Iterable<LegoSet> compare = repository.findAll();

  // verify
  assertThat(actual).as("same number of lego sets").hasSize(Lists.newArrayList(compare).size());
  assertThat(actual.get(0).getModels()).as("same number of models").hasSize(Lists.newArrayList(compare).get(0).getModels().size());
  assertThat(actual.get(0).getModels().get(0)).as("model must not be null").isNotNull();
  assertThat(actual.get(0).getModels().get(0).getName()).as("model must have a name").isNotEmpty();
}

这对引用 2 个Models 的LegoSet 建模。 repository.findByName() 带有自定义查询注释; repository.findAll()CrudRepository 的标准 spring-boot-data 方法(仅供参考)。

版本 1 中的自定义查询:

@Query("SELECT ls.id, ls.name, ls.min_age, ls.max_age, " +
      "h.handbuch_id AS manual_handbuch_id, h.author AS manual_author, h.text AS manual_text " +
      "FROM lego_set ls JOIN handbuch h ON ls.id = h.handbuch_id " +
      "WHERE name = :name")
List<LegoSet> findByName(@Param("name") String name);

在这个版本中,测试失败了

java.lang.AssertionError: [model must not be null] 
Expecting actual not to be null

好的,然后我在model 中添加另一个JOIN

@Query("SELECT ls.id, ls.name, ls.min_age, ls.max_age, " +
      "h.handbuch_id AS manual_handbuch_id, h.author AS manual_author, h.text AS manual_text, " +
      "m.* " +
      "FROM lego_set ls JOIN handbuch h ON ls.id = h.handbuch_id " +
      "JOIN model m ON ls.id = m.lego_set " +
      "WHERE name = :name")
List<LegoSet> findByName(@Param("name") String name);

现在测试失败了

java.lang.AssertionError: [same number of lego sets] 
Expected size:<1> but was:<2> in:
<[LegoSet(id=1, name=Small Car 01, minimumAge=P5Y, maximumAge=P12Y, manual=Manual(id=1, author=Jens Schauder                                                                                       , text=Just put all the pieces together in the right order), models={suv=Model(name=suv, description=SUV with sliding doors.), roadster=Model(name=roadster, description=Slick red roadster.)}),
    LegoSet(id=1, name=Small Car 01, minimumAge=P5Y, maximumAge=P12Y, manual=Manual(id=1, author=Jens Schauder  

那么我该如何正确编写该查询呢?

【问题讨论】:

  • 很好的问题。重现问题轻而易举!谢谢。

标签: java sql spring spring-data spring-data-jdbc


【解决方案1】:

第一个查询实际上是正确的,并且工作正常。

问题出在您的测试中。 modelsMap,但您将其视为 List 进行编译,因为列表索引也是有效的映射键。

如果您像这样更改测试中的最后两个断言,它们将成功:

assertThat(actual.get(0).getModels().get("suv")).as("model must not be null").isNotNull();
assertThat(actual.get(0).getModels().get("suv").getName()).as("model must have a name").isNotEmpty();
// ----------------------------------------^

另一种方法是使用第二个查询,但 with a custom ResultSetExtractor 将多个模型的多行收集到单个 LegoSet

【讨论】:

    【解决方案2】:

    我的情况类似,但我看不出我的情况有什么不同。

    我有三个模型: 客户:身份证,姓名.. 项目:id、name、clientId、List 项目成员

    这是我的编码查询

      @Query("""
           select
              project.id,
              project.legacy_id,
              project.code,
              project.client_id,
              project.is_archived,
              project.name,
              project.budget_type,
              project.hours_budget_max,
              project.money_budget_max
           from project
           join client on client.id = project.client_id
           where client.name ilike '%:name%'
          """)
      List<Project> findByClientNameContainingIgnoreCase(final String name);
    

    如您所见,我正在寻找客户名称(使用连接)匹配模式的项目。

    手动执行请求会给我预期的结果。但是通过spring data jdbc给我没有结果

    【讨论】:

    • 再深入一点,它似乎与我对 '% 和 %' 的使用有关/跨度>
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-09
    • 1970-01-01
    • 2013-11-20
    • 2017-11-13
    • 2022-01-18
    • 2013-12-08
    相关资源
    最近更新 更多