Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/315.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java OneToMany在spring jpa中包含筛选子句的问题_Java_Mysql_Spring_Jpa_Spring Data Jpa - Fatal编程技术网

Java OneToMany在spring jpa中包含筛选子句的问题

Java OneToMany在spring jpa中包含筛选子句的问题,java,mysql,spring,jpa,spring-data-jpa,Java,Mysql,Spring,Jpa,Spring Data Jpa,在SpringJPA中对@OneToMany关系使用时,我当前在MYSQL8/H2测试用例中得到了意外的结果。我想使用JPQL在TKBData表中筛选TKBColumn表列表。我希望得到一个带有过滤TKBColumn的TKBData表,但我总是得到带有所有TKBColumn(未过滤)的TKBData表。当我使用SQL命令时,它可以工作 我不知道这里有什么问题,为什么它总是给我TKBData表,里面总是有所有TKBColumn表 本机查询(此操作有效): 输出 ID NAME 7b6

在SpringJPA中对@OneToMany关系使用时,我当前在MYSQL8/H2测试用例中得到了意外的结果。我想使用JPQL在TKBData表中筛选TKBColumn表列表。我希望得到一个带有过滤TKBColumn的TKBData表,但我总是得到带有所有TKBColumn(未过滤)的TKBData表。当我使用SQL命令时,它可以工作

我不知道这里有什么问题,为什么它总是给我TKBData表,里面总是有所有TKBColumn表

本机查询(此操作有效):

输出

ID      NAME  
7b6ec910-3e53-40a3-9221-ee60e75c8d67    column1
JPQL查询(不起作用):

输出:

id: e892bc28-c35f-4fc8-9b09-387f97a758d8, name:column1
id: 069cc76b-3487-4ad8-a4ae-6568694e2287, name:column2
表“TKBData”

public class TKBData {

    @Id
    @Builder.Default
    private String id = UUID.randomUUID().toString();

    ...

    @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
    @Builder.Default
    private Set<TKBColumn> columns = Sets.newHashSet();
    
    ...
}
Spring数据存储库

@Service
public interface KBDataRepository extends CrudRepository<TKBData, String>, KBDataCustomRepository {

    @Query("select d from TKBData d LEFT JOIN d.columns c WHERE c.name = :name")
    public TKBData filterByColumn(@Param("name") String name);

}
在测试类开始时生成的表的相关内容

Table: TKBDATA

ID
726004cf-5cab-4b1d-bb3f-466ba22622e9


Table: TKBDATA_TKBCOLUMN

TKBDATA_ID                              COLUMNS_ID  
726004cf-5cab-4b1d-bb3f-466ba22622e9    7b4e4ea8-4ff9-4668-8882-67ff93b595ca
726004cf-5cab-4b1d-bb3f-466ba22622e9    d670e813-0466-48a8-be54-ee992cf28462


Table: TKBCOLUMN

ID                                DATAORDER  NAME   OWNERID  
d670e813-0466-48a8-be54-ee992cf28462    0   column1 16e01046-9a84-4651-98d8-4e3e358212eb
7b4e4ea8-4ff9-4668-8882-67ff93b595ca    1   column2 16e01046-9a84-4651-98d8-4e3e358212eb
有关更多信息,请在此处找到github存储库:

测试类:

编辑: 这个问题的解决方案是使用本机查询,因为JPA的设计以及它如何处理对象,这就是为什么我的用例存在这个问题。

  • 从TKBData d中选择d并连接d.c列,其中c.name=column1

  • 查找TKBData对象,该对象具有关联的
    对象,其中
    名称
    列1
  • 一旦它决定哪个TKBData至少有一个
    对象,而
    名称
    列1
    那么它将返回在JPA中您无法控制的所有相关
    对象。(见附件)。另一种方法是编写本机sql并返回自定义的非实体对象
  • 例如,您将
    TKBDATA_1
    column1
    column2
    关联,您还将
    TKBDATA_2
    column3
    关联
  • 运行查询时,它将忽略
    TKBDATA_2
    ,并决定返回
    TKBDATA_1
    ,因为它至少有一个
    对象具有
    名称
    =
    列2
    但在此之后您无法控制要为
    TKBDATA\u 1
    返回哪些关联的
    对象,JPA将返回所有关联的列对象
  • 如果您不确定原因,请阅读hibernate会话。它如何提供内存中任何关联项的唯一表示。它是代码<脏检查> /代码>和代码>可重复读取
  • 的基础。
  • 更新您的
    @OneToMany
    ,如下所示

  • 不要忘记,与sql中的选择不同,这里选择的任何列都表示要选择TKBData对象,并限制返回哪些TKBData对象

  • 因此,要获得与本机sql相同的结果,请使用第二个JPA查询

注意:

即使您在sql查询中使用了左联接,但它实际上是一个内部联接sql查询,因为您还将
where
条件应用于该联接的最右表。

  • 从TKBData d中选择d并连接d.c列,其中c.name=column1

  • 查找TKBData对象,该对象具有关联的
    对象,其中
    名称
    列1
  • 一旦它决定哪个TKBData至少有一个
    对象,而
    名称
    列1
    那么它将返回在JPA中您无法控制的所有相关
    对象。(见附件)。另一种方法是编写本机sql并返回自定义的非实体对象
  • 例如,您将
    TKBDATA_1
    column1
    column2
    关联,您还将
    TKBDATA_2
    column3
    关联
  • 运行查询时,它将忽略
    TKBDATA_2
    ,并决定返回
    TKBDATA_1
    ,因为它至少有一个
    对象具有
    名称
    =
    列2
    但在此之后您无法控制要为
    TKBDATA\u 1
    返回哪些关联的
    对象,JPA将返回所有关联的列对象
  • 如果您不确定原因,请阅读hibernate会话。它如何提供内存中任何关联项的唯一表示。它是代码<脏检查> /代码>和代码>可重复读取
  • 的基础。
  • 更新您的
    @OneToMany
    ,如下所示

  • 不要忘记,与sql中的选择不同,这里选择的任何列都表示要选择TKBData对象,并限制返回哪些TKBData对象

  • 因此,要获得与本机sql相同的结果,请使用第二个JPA查询

注意:


即使您在sql查询中使用了左联接,它实际上也是一个内部联接sql查询,因为您还将
where
条件应用于该联接上最右的表。

使用DISTINCT JPQL关键字

@Query("select distinct d from TKBData d LEFT JOIN d.columns c WHERE c.name = :name")
public TKBData filterByColumn(@Param("name") String name);
或者使用JPA方法命名查询

public TKBData findByColumnsName(String name);

使用独特的JPQL关键字

@Query("select distinct d from TKBData d LEFT JOIN d.columns c WHERE c.name = :name")
public TKBData filterByColumn(@Param("name") String name);
或者使用JPA方法命名查询

public TKBData findByColumnsName(String name);

可能您的关系是多对多的,您正在本机查询中使用连接表。你没有对一对多做任何列映射,关系应该是,一对多。仅当您关心性能或“回溯”对象时,才直接需要映射。这是我读到的。但无论如何,我也尝试过映射,但没有效果。如果你能给我一些提示来解决我的问题,我们欢迎你。问题仍然是为什么我的JPQL过滤查询有(对我来说是错误的)bahaviour。现在我知道您只是使用自动生成的表。您可以使用@joinColumn来避免额外的连接表,这意味着JPA查询的返回值是return
TKBDATA
objects,其中它在l处有
   @OneToMany(fetch = FetchType.EAGER, 
           cascade = CascadeType.ALL, orphanRemoval = true)
   @Builder.Default
   @JoinTable(name = "TKBDATA_TKBCOLUMN", 
           joinColumns = @JoinColumn(name = "TKBDATA_ID"), 
           inverseJoinColumns = @JoinColumn(name = "COLUMNS_ID"))
   private Set<TKBColumn> columns = Sets.newHashSet();
   select d from TKBData d LEFT JOIN d.columns c WHERE c.name = :name
           vs
   select d from TKBData d JOIN d.columns c WHERE c.name = :name
@Query("select distinct d from TKBData d LEFT JOIN d.columns c WHERE c.name = :name")
public TKBData filterByColumn(@Param("name") String name);
public TKBData findByColumnsName(String name);