提问者:小点点

我怎么能得到一个实体与它的引用实体ID在ManyTo多国关系?


我有一个基本的Spring应用程序,它使用hibernate和mapstruct

有两个实体,每个实体都被实现为将其子子实体作为ManyToMore关系中的List属性

所以有

EntityA.class
with List<EntityB> (fetchType Lazy)

反之亦然

现在,当我的客户调用时,它希望得到一个表示如下的DTO:< br >

EntityADTO
with List<Long> entityBIds

如何使我的实体 A 仅包含实体 B 的 ID 最有效,而无需加载完整的实体 B 并在之后对其进行后处理?

多谢!


共2个答案

匿名用户

@ManyToMany关联信息持久化在一个专用(join-)表中,并在访问集合时延迟加载,因此需要另一个查询。

您可以只查询所需的< code>id属性,而不是查询所有关联实体的完整信息。< br >可能的查询如下所示:

// Spring-Data repository (requires an extra interface for the result):
interface IdOnly(){
  Long getId();
}
interface EntityBRepository extends JpaRepository<EntityB, Long> {
  List<IdOnly> getIdByEntityAId(Long enitityAId);
}

// alternative JPQL query (does not need the interface):
@Query("SELECT b.id FROM EntityB b JOIN b.entityAs as a WHERE a.id=:entityAId")
List<Long> getIdByEntityAIdJpaQuery(@Param("enitityAId") Long enitityAId);

这样,只有相关联的EntityA所需的EntityB id才会从数据库中加载。< br >为了进一步优化,还可以编写一个只直接访问连接表的本机查询,这样可以避免所有连接:

@Query(nativeQuery = true, //
        value = "SELECT entityBId FROM entityA_entityB WHERE enitityAId=:enitityAId")
List<Long> getIdByEntityAIdNative(@Param("enitityAId") Long enitityAId);

为了在使用< code>mapstruct进行映射时执行查询,可以使用spring repository bean,如下所述:https://stackoverflow.com/a/51292920

匿名用户

除了@Fladdimir的回答这是一个很好的方法,如果你只是偶尔需要值列表,JPA允许定义实体图,它可以指定你想要加载的对象图中的内容。这可以允许你从图中的子/引用实体中定义你的实体和特定属性,允许返回对象,但取消获取大部分数据。这可以允许你处理实体B实例,但没有完全填充它们。有很多教程,但我不止一次引用https://www.baeldung.com/jpa-entity-graph。正如引用的教程提到的那样,Hibernate可能在如何处理通常急切获取的属性方面存在一些问题,因此它可能无法以您想要的方式工作(但在其他JPA提供程序(如Eclipse Link)中会这样做,这就是我使用它的地方)。

或者,如果这是您将经常需要/需要的 ID 集合,则可以修改对象模型以使其以不同的方式提取。

public class EntityA {
  ..
  @ElementCollection
  @CollectionTable(name = "RELATION_TABLE_NAME", joinColumns = @JoinColumn(name = "A_ID", insertable=false, updatable=false))
  @Column(name = "B_ID", insertable=false, updatable=false)
  List<Long> bIds;
}

这允许在您的 AEntity 中自动获取外键。我已将其设置为只读,假设您将保留现有的 A-

如果这是一个问题,您可以再次更改内容,并删除现有的a-

public class EntityA {
  ..
  @ElementCollection
  @CollectionTable(name = "RELATION_TABLE_NAME", joinColumns = @JoinColumn(name = "A_ID"))
  List<AB> listOfBs;
}

@Embeddable
public class AB {
  @Column("B_ID", insertable=false, updatable=false)
  Long bId;
  
  @ManyToOne(fetch=LAZY)
  @JoinColumn(name = "B_ID")
  B b;
}

这将允许您获取A并使用B的ID值,而无需从B表中获取。请注意,我已将基本bId属性标记为只读,假设您现有的应用程序将通过为关系分配B引用来设置内容,但您可以将关系标记为只读,并使用bId设置FK值。从长远来看,这可能更有效,因为您不必查找B实例来设置关系。

或者,您可以使AB成为一个实体而不是可嵌入的,并允许它在As和Bs之外存在和被查询。虽然有相当多的选项,以及映射它的方法,但是对于一个简单的模型和用例来说可能不是必需的。