简体   繁体   中英

Hibernate - Persisting child entity containing parent entity

Getting errors while trying to persist child entity (MsgRetry) when trying to get an entity of parent entity (Msg) where the parent PK (msg_id) is the FK in the child entity.

Errors like: org.hibernate.id.IdentifierGenerationException: attempted to assign id from null one-to-one property

The parent entity, does not need to know about the child entity (at least i don't think it needs to, to work). Once the child entity is persisted I'm trying to also persist the parent entity. I can work around this by not having the parent entity in the child entity and the call the associated repositories. However, I don't think it's as clean as what I'm attempting but obviously more difficult/ complex.

Thanks for any advice on best practices or how to achieve this if this is a good solution.

tables:

msg
msg_id pk
msg_status msg_status
msg_retry
msg_id fk
count
timestamp

model:

@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);
    }

Errors out: org.springframework.orm.jpa.JpaSystemException: ids for this class must be manually assigned before calling save(): msgtest.MsgRetry;

how about add one id fields to MsgRetry class

First, straighten out your IDs for MsgRetry . The FK should be good enough.

@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; }
}

Next, be sure MsgRetryRepository is properly sub-classed:

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

Lastly, query the MsgRetry in the right way:

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);
        }   
    }
}

What is your persistence layer? Maybe you can turn on debugging and visit the logs to see what is happening under the hood.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM