mysql - 如何使用 spring-data-jpa 对具有持久关系的实体执行 native 查询

标签 mysql regex hibernate jpa spring-data-jpa

我正在尝试对 mysql 5.7 数据库使用 spring-data-jpa 来使用正则表达式查找实体。我对 jpaRepository 方法的 native 查询产生错误。

我正在用 Spring 替换用于许可的旧的定制 C++ 服务器。我无法更改数据库结构或 API。 我正在使用 spring-boot-starter-data-jpa:2.1.4.RELEASE,它的用户是 hibernate-core:5.3.9.Final 和 spring-data-jpa:2.1.6:RELEASE。 我的 api 实现以下端点: licenses/search/{fieldName}:{regex}/{limit}/{offset} 例如:licenses/search/edition.name:"^Edition X$"/1/0

我的 DBLicense 实体与 DBEdition 具有 @OneToMany 关系。

首先,我尝试在 LicenseRepository 中编写查询方法,如here所述。 :

@Repository
public interface LicenseRepository extends JpaRepository<DBLicense, Long> {
...
List<DBLicense> findByEditions_NameRegex(String searchStr, Pageable pageRequest);
...
}

但我不断收到以下错误:不支持的关键字正则表达式 (1): [matchesregex, matches, regex]。文档表明regex might not be supported ,并检查我找不到的特定于商店的文档。 Other answers让我尝试了 @Query 注释。

因为JPQL does not support regex ,我选择使用原生查询:

@Repository
public interface LicenseRepository extends JpaRepository<DBLicense, Long> {
...
    @Query(value = "select l.* from licenses as l join licenseeditions as le on l.LicenseID=le.LicenseID join editions as e on le.EditionID=e.EditionID where e.Name regexp :searchStr limit :offset, :limit", nativeQuery = true)
    List<DBLicense> findByEditions_NameRegex(@Param("searchStr") String searchStr, @Param("offset") Integer offset, @Param("limit") Integer limit);
...
}

我收到以下错误:

2019-07-18 11:46:50.145  WARN 24524 --- [nio-8080-exec-2] o.h.engine.jdbc.spi.SqlExceptionHelper   : SQL Error: 0, SQLState: S0022
2019-07-18 11:46:50.146 ERROR 24524 --- [nio-8080-exec-2] o.h.engine.jdbc.spi.SqlExceptionHelper   : Column 'ParentID' not found.

我的 DBLicense 类(class):

@Entity
@Table(name = "licenses")
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class DBLicense {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "LicenseID")
...
    @ManyToOne
    @JoinTable(name = "licensekinships", joinColumns = @JoinColumn(name = "ChildID", referencedColumnName = "LicenseID"), inverseJoinColumns = @JoinColumn(name = "ParentID", referencedColumnName = "LicenseID"))
    private DBLicense parentLicense;
...
    @OneToMany
    @JoinTable(name = "licenseeditions", joinColumns = @JoinColumn(name = "LicenseID", referencedColumnName = "LicenseID"), inverseJoinColumns = @JoinColumn(name = "EditionID", referencedColumnName = "EditionID"))
    @Setter(AccessLevel.NONE)
    @Builder.Default
    private List<DBEdition> editions = new ArrayList<DBEdition>();
}

查询在mysql中执行成功(我检查了日志),在Spring内部返回后有时会抛出错误。

请注意,我的 @Query 中引用的表(即许可证、许可证版本、版本)都不包含“ParentID”列。在licensekinships上找到‘ParentID’,这是license与license之间多对一关系的关系表。

我的本​​机查询是否需要考虑 DBLicense 上的所有其他关系注释?这是有问题的,因为有很多(内置的 LicenseRepository findById 方法执行不少于 59 个查询!)。

最佳答案

如果您在实体上使用 hibernate/javax.persistence 关系注释(即 @OneToOne、@OneToMany、@ManyToOne、@ManyToMany),并且您尝试使用 native 查询,那么您可能会遇到与在问题帖子中提出。

如果您有一个复杂的架构,其中一个实体与另一个实体共享关系,而另一个实体又具有进一步的关系,并且您尝试从 native 查询返回其中一个实体,则尤其会发生这种情况。要修复此错误,您需要在 spring-data-jpa 的 native 查询中提供足够的信息,以解析实体中存在的关系。

例如,考虑以下类对象:

@Entity
@Table(name = "entity_a")
public class EntityA {
  @Column
  private int entityA_field
  ...
  @ManyToOne
  private EntityB entityB
}

@Entity
@Table(name = "entity_b")
public class EntityB {
  @Column
  private int entityB_field
  ...
  @ManyToOne
  private EntityC entityC
}

EntityA id 的 JpaRepository 内置 findById 方法可能会执行多个数据库查询。使用sql数据库,例如:

select a.*, b.* from entity_a as a left outer join entity_b as b on a.id = b.id;
select b.*, c.* from entity_b as b left outer join entity_c as c on b.id = c.id;

您将需要模仿第一个查询的连接和列。幸运的是,您可以通过打开日志记录看到 spring-data-jpa 生成的伪sql:

  1. 查找并打开您的 application.properties(或 application.yaml)文件。通常位于“src/main/resources”中。
  2. 添加以下行(如果不存在):spring.jpa.show-sql=true,然后保存。
  3. 为您的 native 查询返回的实体创建一个存储库。例如,如果您的 native 查询返回 EntityA,那么您的存储库可能如下所示:
@Repository
public interface MyRepository extends JpaRepository<EntityA, Long> {}
  • 调用存储库的 findById 方法(从 Controller 或测试)并检查控制台输出。许多查询将记录到控制台。您的 native 查询需要提供与第一个查询相同的列并实现相同的联接。
  • 关于mysql - 如何使用 spring-data-jpa 对具有持久关系的实体执行 native 查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57100428/

    相关文章:

    mysql - 添加左连接后结果减少

    php - Laravel 5 - 如何在同一张表上执行左连接

    sql - MySQL应该做多少计算?

    asp.net - 识别 0.0 和 1.0 之间的小数的正则表达式

    javascript - 删除任何非数字并检查是否格式化为有效数字

    Javascript RegEx 正面前瞻未按预期工作

    java - Spring Data REST - 检测到具有相同关系类型的多个关联链接

    php - 如何显示每篇文章总评论数

    java - 使用 jboss 工具/hibernate 配置连接到数据库时出错

    java - 如何在 hibernate 中为@ElementCollection 设置表名