首页 > 解决方案 > Spring Boot Jpa JPQL 选择除特定列之外的列

问题描述

例如,我有两个具有OneToOne关联的实体。

@Entity
class Entity1(
    @Column val columnToSelect1: String,
    @Column val columnToSelect2: String,
    @Column val columnToSelect3: String,
    @Column val columnToSelect4: String,
    @Column val columnToSelect5: String,
    @Column val columnToSelect6: String,
    @Column val columnToSelect7: String,
    @Column val columnToSelect8: String,
    @Column val columnToSelect9: String,
    @Column val columnToSelect10: String,


    @OneToOne
    @JoinColumn
    val columnNotToSelect: Entity2
)

而且,有很多次我想选择特定列(如val columnNotToSelect: Entity2.
这是因为选择Entity2会导致触发另一个并非总是需要的查询。

现在,我正在实现这样的要求。

interface Entity1Getter {
    fun getColumnToSelect1(): String
    fun getColumnToSelect2(): String
    fun getColumnToSelect3(): String
    ...
}

interface Entity1CrudRepository : CrudRepository<Entity1, UUID> {
    // select all columns
    fun findAll(): List<Entity1>

    // select all columns except columnNotToSelect
    @Query(
        "SELECT " +
        "e.columnToSelect1 as columnToSelect1" +
        "e.columnToSelect2 as columnToSelect2" +
        "e.columnToSelect3 as columnToSelect3" +
        "e.columnToSelect4 as columnToSelect4" +
        "e.columnToSelect5 as columnToSelect5" +
        "e.columnToSelect6 as columnToSelect6" +
        "e.columnToSelect7 as columnToSelect7" +
        "e.columnToSelect8 as columnToSelect8" +
        "e.columnToSelect9 as columnToSelect9" +
        "e.columnToSelect10 as columnToSelect10" +
        "FROM Entity1 e"
    )
    fun findAllExceptOneColumn(): List<Entity1Getter>
}

我必须安排我想要查询的所有列,这是非常低效的。

问题

  1. 除了特定列之外,还有其他选择方法吗?
  2. 或者,有什么不同的方法可以不选择关联的列?(不触发另一个查询)

谢谢:D

标签: springspring-bootjpaspring-data-jpaspring-data

解决方案


JPA 世界中所需的行为称为 EntityGraph. 您可以创建一个特定的实体图(或一组图,如果需要多个)。然后标记一个特定的查询方法来使用这个实体图。作为返回结果,您将获取原始实体,但不在图中的所有其他属性将处于 LAZY 获取模式。

例如:

@NamedEntityGraph(
    name = "Entity1.exceptColumn", 
    attributeNodes = {
        @NamedAttributeNode("columnToSelect1"), 
        @NamedAttributeNode("columnToSelect2"), 
        @NamedAttributeNode("columnToSelect3"), 
        @NamedAttributeNode("columnToSelect4"), 
        @NamedAttributeNode("columnToSelect5"), 
        @NamedAttributeNode("columnToSelect6"), 
        @NamedAttributeNode("columnToSelect7"), 
        @NamedAttributeNode("columnToSelect8"), 
        @NamedAttributeNode("columnToSelect9"), 
        @NamedAttributeNode("columnToSelect10")
    }
)
@Entity
class Entity1(
    @Column val columnToSelect1: String,
    @Column val columnToSelect2: String,
    @Column val columnToSelect3: String,
    @Column val columnToSelect4: String,
    @Column val columnToSelect5: String,
    @Column val columnToSelect6: String,
    @Column val columnToSelect7: String,
    @Column val columnToSelect8: String,
    @Column val columnToSelect9: String,
    @Column val columnToSelect10: String,

    @OneToOne
    @JoinColumn
    val columnNotToSelect: Entity2
)

然后在您的数据存储库中:

interface Entity1CrudRepository : CrudRepository<Entity1, UUID> {
    // select all columns
    fun findAll(): List<Entity1>

    // select all columns except columnNotToSelect
    @EntityGraph(value = "Entity1.exceptColumn")
    @Query("SELECT e FROM Entity1 e ")
    fun findAllExceptOneColumn(): List<Entity1>

}

注意:您使用的是同一个Entity1类,但实体图中的属性以 LAZY fetch 模式标记。

实现此目的的其他方法是使用投影查询,在这种情况下,您正在创建 DTO,并为此编写查询:

data class Entity1Projection (
    val columnToSelect1: String,
    val columnToSelect2: String,
    val columnToSelect3: String,
    val columnToSelect4: String,
    val columnToSelect5: String,
    val columnToSelect6: String,
    val columnToSelect7: String,
    val columnToSelect8: String,
    val columnToSelect9: String,
    val columnToSelect10: String
)

然后在您的存储库中,您可以定义以下内容:

interface Entity1CrudRepository : CrudRepository<Entity1, UUID> {
    // select all columns
    fun findAll(): List<Entity1>

    // select all columns except columnNotToSelect
    @Query("""
    SELECT new fully.qualified.package_name.Entity1Projection(
        e.columnToSelect1, 
        e.columnToSelect2, 
        e.columnToSelect3, 
        e.columnToSelect4, 
        e.columnToSelect5, 
        e.columnToSelect6, 
        e.columnToSelect7, 
        e.columnToSelect8, 
        e.columnToSelect9, 
        e.columnToSelect10
    ) 
    FROM Entity1 e """)
    fun findAllExceptOneColumn(): List<Entity1Projection>

}

每种方法都有其优点和缺点,您决定使用哪种方法。


推荐阅读