在同一事务中查找实体时,多对一关系始终为空

Posted

技术标签:

【中文标题】在同一事务中查找实体时,多对一关系始终为空【英文标题】:ManyToOne relationship is always null when finding entity in the same transaction 【发布时间】:2021-05-07 01:01:07 【问题描述】:

我有一个与 ModeratorEntity 具有多对一关系的 ConversationEntity

@Entity
@Table(name="CONVERSATIONS")
public class ConversationEntity 

    @Id
    private Integer id;
    
    private Integer moderatorId;

    @ManyToOne
    @JoinColumn(name="moderatorId", insertable=false, updatable=false)
    private ModeratorEntity moderator;


@Entity
@Table(name="MODERATORS")
public class ModeratorEntity 

    @Id
    private Integer id;
    
    private Integer name;

还有一个带有事务方法的服务类,它首先保存 ModeratorEntity,然后保存之前创建的具有 moderatorId 的 ConversationEntity

    @Transactional
    public void doStuff(Moderator moderator, Integer conversationId) 
        Integer moderatorId = moderatorService.save(moderator);
        Integer conversationId = conversationService.save(conversationId, moderatorId);

        //do other stuff

        Conversation conversation = conversationService.findById(conversationId);
    

当我试图通过同一事务中的 id 查找 ConversationEntity 时,下面几行,我得到了设置了字段 moderatorId 但 ModeratorEntity 对象 = null 的 ConversationEntity。

如果我在事务之外执行此操作,我将正确设置 ModeratorEntity 对象。

我尝试在 ModeratorRepository 和 ConversationRepository 中使用 saveAndFlush 并在 ManyToOne 关系中设置 FetchType.EAGER 但它们都不起作用

【问题讨论】:

你认为FK字段应该是insertable=false, updatable=false 这样没有问题。问题是为什么如果我在同一个事务中发现存储库返回一个非空 id 但一个空相关实体 @AlejandroCuervo 也许你应该使用name="moderatorId" 而不是name="moderator_id" 与数据库字段的映射是正确的。我想应该是交易出了点问题 【参考方案1】:

有很多关于类似问题的问题。例如@Transactional in bidirectional relation with Spring Data returns null 和Hibernate: comparing current & previous record。

只要您在单个事务中,您将始终获得相同的实例,并且实际上不会从数据库中加载任何数据。而且因为(至少看起来)你从来没有设置对ModeratorEntity的引用,所以它保持null

一旦您处于新事务中,就会访问数据库并且 JPA 会填充一个新实例,现在包括一个 ModeratorEntity 引用。

因此,可能的修复方法是:

moderatorService.save 返回一个实体并将其设置在Conversation 中,而不是一个id。您不妨放弃moderatorId。这是使用 JPA 做事的惯用方式。

在单独的事务中执行查询。弹簧TransactionTemplate 可能会派上用场。虽然这确实有效,但它会导致 JPA 内部渗透到您的应用程序中,我建议您避免这样做。

【讨论】:

在保存之前在 ConversationEntity 中设置 moderatorEntity 对我有用!!!谢谢

以上是关于在同一事务中查找实体时,多对一关系始终为空的主要内容,如果未能解决你的问题,请参考以下文章

如何防止 EntityType 在与同一实体(父)的多对一关系中显示当前对象?

核心数据获取多对一关系对象

关联映射级联操作关系维护 ---- Hibernate之一对多|多对一关系

Hibernate中一对多和多对一关系

Hibernate多表关系配置——多对一关系映射

MyBatis之多对一关系