【问题标题】:Hibernate - Persisting child entity containing parent entityHibernate - 包含父实体的持久子实体
【发布时间】:2022-01-27 01:19:59
【问题描述】:

在尝试获取父实体 (Msg) 的实体时尝试持久化子实体 (MsgRetry) 时出错,其中父 PK (msg_id) 是子实体中的 FK。

类似的错误:org.hibernate.id.IdentifierGenerationException: 试图从空的一对一属性分配 id

父实体不需要知道子实体(至少我认为它不需要知道)。一旦子实体被持久化,我也试图持久化父实体。我可以通过在子实体中没有父实体并调用关联的存储库来解决这个问题。但是,我认为它不像我正在尝试的那样干净,但显然更困难/复杂。

感谢您就最佳实践或如果这是一个好的解决方案如何实现这一目标提供任何建议。

表格:

msg
msg_id pk
msg_status msg_status
msg_retry
msg_id fk
count
timestamp

型号:

@Entity
@Table(name="msg")
public class Msg {
    
    @Id
    @Column(name = "msg_id")
    @GeneratedValue(strategy = generationtype.sequence, generator = "msg_id_seq_gen")
    @SequenceGenerator(name = "msg_id_seq_gen", sequencename = "msg_id_seq", allocationsize = 1)
    private Long msgId;
    
    @Column(name = "msg_status", nullable = false)
    private String msgStatus;
    
    ...
    
    //getters setters
}
@Entity
@Table(name = "msg_retry")
public class MsgRetry implements Serializable{

    private static final long serialVersionUID = -7637385223556379976L;

    @Id
    @Column(name = "msg_id")
    private Long msgId;
    
    @OneToOne
    @JoinColumn(name="msg_id", referencedColumnName = "msg_id")
    private Msg msg;
    
    @Column(name = "count")
    private Long count;
    
    @Generated(value = GenerationTime.ALWAYS)
    @Column(name = "timestamp")
    private Date timestamp;
    
    
    
    public MsgRetry() {
    }

    public MsgRetry(Msg msg, Long count) {
        this.msg = msg;
        this.count = count;
    }
    
    public MsgRetry(Long msgId, Long count) {
        this.msgId = msgId;
        this.count = count;
    }
    
    public Msg getMsg() {
        return msg;
    }

    public void setMsg(Msg msg) {
        this.msg = msg;
    }
@Repository
public interface MsgRetryRepository extends JpaRepository<MsgRetry, Long>{

}
@Test
    public void testSaveMsgByMsgIdRetry() {
        
        msgRetryRepository.deleteAll();
        List<Msg> msgs = msgRepository.findAll();
        
        MsgRetry msgRetry = new MsgRetry(msgs.get(0).getMsgId(), 1L);
        
        msgRetry = msgRetryRepository.save(msgRetry);
        assertNotNull(msgRetry.getMsg());  // fails to load Msg entity
        LOG.info("msgRetry: {}", msgRetry);
    }
@Test
    public void testSaveMsgRetryByMsg() {
        
        msgRetryRepository.deleteAll();
        List<Msg> msgs = msgRepository.findAll();
        
        MsgRetry msgRetry = new MsgRetry(msgs.get(0), 1L);
        
        msgRetry = msgRetryRepository.save(msgRetry);
        assertNotNull(msgRetry.getMsg());
        LOG.info("msgRetry: {}", msgRetry);
    }

错误输出:org.springframework.orm.jpa.JpaSystemException:必须在调用 save() 之前手动分配此类的 ID:msgtest.MsgRetry;

【问题讨论】:

    标签: java hibernate jpa spring-data-jpa


    【解决方案1】:

    首先,整理一下MsgRetry 的 ID。 FK应该足够好。

    @Entity
    @Table(name = "msg_retry")
    public class MsgRetry {
        @Id
        @ManyToOne(optional = false)
        @JoinColumn(name = "msg_id")
        private Msg msg;
        
        @Column(name = "count")
        private Long count;
        
        @Generated(value = GenerationTime.ALWAYS)
        @Column(name = "timestamp")
        private Date timestamp;
        
        public Msg getMsg() { return msg; }
             
        public void setMsg(Msg msg) { this.msg = msg; }
    }
    

    接下来,确保 MsgRetryRepository 被正确子分类:

    public interface MsgRetryRepository extends CrudRepository<MsgRetry, Msg>
    {
      // Empty for now
    }
    

    最后,以正确的方式查询MsgRetry

    public class BizLogic {
    
        MsgRetryRepository retryRepo
        
        public MsgRetry retry(Msg msg, String msgStatus) {
        
            MsgRetry mr = retryRepo.findById(msg);        
            if (mr !=null) {
                // XXX I cannot tell from your logic what you are doing here.
                retryRepo.save(mr);
            }   
        }
    }
    

    你的持久层是什么?也许您可以打开调试并访问日志以查看幕后发生的事情。

    【讨论】:

    • 我编辑了与存储库代码一起发布的代码。我不清楚是否需要在 MsgRetry 实体中使用 @Id,其中 msg_id 是来自 Msg 表的 FK。 MsgRetry 是否需要它自己的 PK 或者它的 PK 是否可以是另一个表中的 FK(很抱歉在这方面丢失了一点)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-09-22
    • 2015-04-15
    • 2011-11-20
    • 1970-01-01
    • 2016-05-17
    • 1970-01-01
    • 2011-08-09
    相关资源
    最近更新 更多