如何将 FindAllBy 与 JpaRepository 中的多个字段一起使用?

Posted

技术标签:

【中文标题】如何将 FindAllBy 与 JpaRepository 中的多个字段一起使用?【英文标题】:How to use FindAllBy with multiple fields in a JpaRepository? 【发布时间】:2019-08-09 18:45:31 【问题描述】:

您可以在下面找到一个显示我的问题的最小示例:

src/main/kotlin/com/mytest/findallbytest/Application.kt:

package com.mytest.findallbytest

import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication

@SpringBootApplication
class MyTestApplication

fun main(args: Array<String>) 
    runApplication<MyTestApplication>(*args)

src/main/kotlin/com/mytest/findallbytest/model/Thing.kt:

package com.mytest.findallbytest.model

import org.springframework.data.jpa.domain.AbstractPersistable
import javax.persistence.Entity
import javax.persistence.Table

@Entity
@Table(name = "things")
class Thing(
        val foo: Long,
        val bar: Long
) : AbstractPersistable<Long>()

src/main/kotlin/com/mytest/findallbytest/repository/ThingRepository.kt:

package com.mytest.findallbytest.repository

import com.mytest.findallbytest.model.Thing
import org.springframework.data.jpa.repository.JpaRepository

interface ThingRepository : JpaRepository<Thing, Long> 
    fun findAllByFooAndBar(foos: Iterable<Long>, bars: Iterable<Long>): Iterable<Thing>

src/main/resources/application.yml:

spring:
  datasource:
    url: jdbc:h2:mem:db;MODE=PostgreSQL

src/main/resources/db/migration/V1__things.sql:

CREATE SEQUENCE HIBERNATE_SEQUENCE;

CREATE TABLE things (
    id      BIGINT PRIMARY KEY NOT NULL,
    foo     BIGINT NOT NULL,
    bar     BIGINT NOT NULL
);

src/test/kotlin/com/mytest/findallbytest/FullTest.kt:

package com.mytest.findallbytest

import com.mytest.findallbytest.model.Thing
import com.mytest.findallbytest.repository.ThingRepository
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.test.context.junit.jupiter.SpringExtension

@ExtendWith(SpringExtension::class)
@SpringBootTest
class FullTest 

    @Autowired
    lateinit var repo: ThingRepository

    @Test
    fun `basic entity checks`() 
        repo.save(Thing(1, 2))
        repo.save(Thing(3, 4))
        repo.save(Thing(1, 4))
        assertThat(repo.findAll()).hasSize(3)

        // ERROR: Expected size:<2> but was:<0>
        assertThat(repo.findAllByFooAndBar(listOf(1L, 3L), listOf(2L, 4L))).hasSize(2)
    

问题是,findAllByFooAndBar 返回一个空列表。但是我希望它返回三个已保存实体中的前两个。

我做错了什么,我的目标或查询多个实体,匹配多个字段,如何实现?

【问题讨论】:

【参考方案1】:
fun findAllByFooInAndBarIn(foos: Iterable<Long>, bars: Iterable<Long>): Iterable<Thing>

【讨论】:

感谢您的快速回答,但findAllByFooInAndBarIn 也返回一个空列表。另外,我希望查询不包括Thing(1, 4)。刚刚相应地编辑了我的问题。【参考方案2】:

一个(不是很好)解决方案是手动创建一个查询并使用EntityManager 发送它:

@Repository
class SecondThingRepository(private val entityManager: EntityManager) 
    fun selectByFoosAndBars(foosAndBars: Iterable<Pair<Long, Long>>): Iterable<Thing> 
        val pairsRepr = foosAndBars.joinToString(prefix = "(", postfix = ")")  "($it.first, '$it.second')" 
        val query: TypedQuery<Thing> = entityManager.createQuery("SELECT t FROM Thing t WHERE (t.foo, t.bar) IN $pairsRepr", Thing::class.java)
        return query.resultList
    

然后:

repo2: SecondThingRepository
...
assertThat(repo2.selectByFoosAndBars(listOf(Pair(1L, 2L), Pair(3L, 4L)))).hasSize(2)

【讨论】:

以上是关于如何将 FindAllBy 与 JpaRepository 中的多个字段一起使用?的主要内容,如果未能解决你的问题,请参考以下文章

创建一个简单的“ORM/ActiveRecord”模式

spring boot快速入门 5: 事务管理

Grails 重定向中断参数类型

Swinject:如何将委托模式与接口隔离(类与接口)一起使用?

如何将 'afterColumnResize' 事件与 'rhandsontable' 一起使用?

如何将 Quickblox 与 angularjs 集成?