从数据库返回的对象列表为空

Posted

技术标签:

【中文标题】从数据库返回的对象列表为空【英文标题】:List on object returned from database empty 【发布时间】:2021-03-07 10:31:21 【问题描述】:

我有三个构成多对多关系的数据库表。这些表名为 Disposition、Disposition_Filter 和 Dispositions_Disposition_Filter。已经提到,Disposition_Disposition_Filter 是“连接表”。

DispositionFilterEntity 类如下所示:

@Getter
@Setter
@ToString
@EqualsAndHashCode
@NoArgsConstructor
@AllArgsConstructor
@Entity(name = "disposition_filter")
public class DispositionFilterEntity 
  @GenericGenerator(name = "uuid2", strategy = "org.hibernate.id.UUIDGenerator")
  @GeneratedValue(generator = "uuid2")
  @Id
  private String id;

  @Column private String name;

而 DispositionEntity 类看起来像这样:

@Getter
@Setter
@ToString
@EqualsAndHashCode
@Entity(name = "dispositions")
public class DispositionEntity 
  @GenericGenerator(name = "uuid2", strategy = "org.hibernate.id.UUIDGenerator")
  @GeneratedValue(generator = "uuid2")
  @Id
  private String id;

  /** @see Disposition */
  @Column(nullable = false)
  private String name;

  @Column(nullable = false)
  private String description;

  @Column(nullable = false)
  private String category;

  @Column private boolean active;

  @Column private String label;

  @Column(name = "hidden_if_agent_not_assigned")
  private Boolean hidden;

  @Transient
  public Disposition getAttributeTypeEnum() 
    return Disposition.from(name);
  

  @ManyToMany(fetch = FetchType.LAZY)
  @JoinTable(
    name = "dispositions_disposition_filter",
    joinColumns = @JoinColumn(name = "filter_id"),
    inverseJoinColumns = @JoinColumn(name = "disposition_id"))
  private List<DispositionFilterEntity> filters;

当我在调试器中运行我的代码并请求从数据库中检索所有处置过滤器对象时,我可以看到处置对象上的过滤器成员返回为空,尽管事实上数据确实存在于那种关系。如果有人知道为什么该列表是空的并能指出我正确的方向,我将非常感激。

【问题讨论】:

始终查看生成的查询。 您在查看 DispositionEntity.filters 列表吗?可能想要检查映射和列表本身,因为它看起来像一个自我引用。由于没有指定连接表的多对多,因此它没有使用您在描述中提到的 3 个表之一。从“过滤器”名称来看,我认为您的意思是让列表包含 DispositionFilterEntity 并且 ManyToMany 应该指定一个 mappedby="dispositions" Shadov,你能发布如何显示生成的查询吗? @Chris 仍然有这个问题,尽管已将 ManyToMany 更新为 DispositionFilterEntities 列表(应该是这样)并且我添加了 mappedBy="dispositions" 但仍然从数据库作为 DispositionFilterEntity 上的一个空列表。 您是从数据库中获取实体,还是可能已缓存?如果您只是持久化实体并使用相同的 EntityManager 上下文,请确保您的应用程序设置了关系的双方 - 您得到的只是您设置的内容,除非您强制从数据库刷新。至于 Sql - 检查您的 JPA 提供程序的日志记录。 【参考方案1】:

正如您在第二次更新中意识到的那样,您的第一个问题与您在 DispositionFilterEntity 中配置 dispositions 关系的方式有关,您互换了 joinColumnsinverseJoinColumns 属性中的列名称。而不是这个:

@ManyToMany
@JoinTable(
  name = "dispositions_disposition_filter",
  joinColumns = @JoinColumn(name = "disposition_id"),
  inverseJoinColumns = @JoinColumn(name = "filter_id"))
private List<DispositionEntity> dispositions;

你需要:

@ManyToMany
@JoinTable(
  name = "dispositions_disposition_filter",
  joinColumns = @JoinColumn(name = "filter_id"),
  inverseJoinColumns = @JoinColumn(name = "disposition_id"))
private List<DispositionEntity> dispositions;

我认为获取类型与问题无关,尽管总是建议延迟获取集合。

现在,您面临堆栈溢出错误。

此错误的原因是您正在以循环方式同时解决两个关系。

我的意思是,例如,您正在从数据库中获取DispositionFilterEntity

在您的代码中,您正在解决与dispositions 的关系,或者通过在代码中调用getDispositions 显式地解决,或者通过其他方式隐式地解决 - 我们稍后会看到这种情况。

对于提取的每个DispositionEntity,您正在再次解决与filters 的关系,或者通过在代码中显式调用getFilters,或者通过其他方式隐式调用。

正如在不同的 cmets 中所指出的,您遇到的第一个堆栈溢出是由您的实体的 toStringequalshashCode 的实现引起的。在实体中的这些方法的实现中不包含任何关系字段始终是一个好习惯,以避免延迟初始化或您面临的其他问题

就您使用 Lombok 而言,为了防止出现错误,您需要使用 @ToString.Exclude@EqualsAndHashCode.Exclude 注释 DispositionFilterEntity 中的 dispositions 字段。

此外,您还可以在DispositionEntity中的filters字段中以相同的方式进行注释。

解决此问题后,您将面临新的堆栈溢出错误。这次错误是由您用于将实体转换为 DTO 的逻辑引起的。

您正在为此使用 Mapstruct。

首先,提供的堆栈跟踪 - 尽管您稍后提供的源代码不包括最初指出的所有方法 - 显示了与不同实体-DTO 对的转换相关的方法。我认为为每个实体-DTO 对使用一个 Mapper 总是更好。

回到堆栈溢出错误,您必须避免的一个选项是通过提供相应的 @Mapping 注释来忽略相应映射方法中的字段之一,dispositionsfilters:它们,这将取决于您的实际用例。

注释正确的映射器方法很重要,在这种情况下,是将每个实体映射到相应 DTO 的方法,而不是相反。

我最初建议您处理 JSON 序列化和应用 @JsonIgnore 或任何您需要的东西来防止错误,但可能,因为您已经有一个 DTO,它将不再需要。

当然,如果您不需要关系是双向的,一种可能的解决方案是删除关系的一侧。 filters 字段没有为您提供任何结果的原因是因为您再次交换了 joinColumnsinverseJoinColumns 的值。而不是这个:

@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(
  name = "dispositions_disposition_filter",
  joinColumns = @JoinColumn(name = "filter_id"),
  inverseJoinColumns = @JoinColumn(name = "disposition_id"))
private List<DispositionFilterEntity> filters;

你需要:

@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(
  name = "dispositions_disposition_filter",
  joinColumns = @JoinColumn(name = "disposition_id"),
  inverseJoinColumns = @JoinColumn(name = "filter_id"))
private List<DispositionFilterEntity> filters;

请始终记住,inverseJoinColumns 引用该列以与适用于集合另一端的实体连接。

【讨论】:

评论不用于扩展讨论;这个对话是moved to chat。

以上是关于从数据库返回的对象列表为空的主要内容,如果未能解决你的问题,请参考以下文章

django model filter变量为空则筛选全部

java中当表中没有记录,为空的时候,用jpa查询的结果返回的是null吗?

休眠从对象中延迟获取嵌套列表

当某个值返回为空时,如何使用下拉列表中的选定值?

Python:返回从列表中过滤的对象的 index() 列表

如果值为空,如何将值返回给 sqldatareader?