maris
maris

Reputation: 776

IdentifierGenerationException: attempted to assign id from null one-to-one property + @MapsId + OneToOne bidirectional

I'm getting error

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

The code snippets:

User.java

@Entity
@Table(schema = "public", name = "user_01")
public class User {

    @Id
    @GeneratedValue(generator = "UUID")
    @GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator")
    @Column(name = "id", updatable = false, nullable = false)
    private UUID id;    
    
    @OneToOne(cascade = CascadeType.ALL)
    @PrimaryKeyJoinColumn
    @JoinColumn(name = "user")
    private UserInformation userInformation;

UserInformation .java

@Entity
@Table(schema = "public", name = "user_information_06")
public class UserInformation {

    @Id
    @Column(name = "id")
    private UUID id;    
    
    @MapsId
    @OneToOne(mappedBy = "userInformation")
    private User user;

UserInformationService.java

// CREATE
public UserInformationBean createUserInformation(UserInformationBean userInformationBean) {
    if(userInformationBean == null || userInformationBean.getUserId() == null)
        return null;

    User user = userRepository.findById(userInformationBean.getUserId()).orElse(null);
    if(user == null)
        return null;
    
    UserInformation userInformation = user.getUserInformation();
    if(userInformation != null) {
        System.err.println("User Information exists !! " + userInformation.getId());
        return null;
    }
    
    userInformation = new UserInformation();        
    userInformation.setFirstname(userInformationBean.getFirstname());
    userInformation.setLastname(userInformationBean.getLastname());
    userInformation.setGender(userInformationBean.getGender());
    userInformation.setDateOfBirth(userInformationBean.getDateOfBirth());
    userInformation.setProfession(userInformationBean.getProfession());
    userInformation.setUpdatedOn(Timestamp.valueOf(LocalDateTime.now()));
    
    user.setUserInformation(userInformation);
    userInformation.setUser(user);
    
    user = userRepository.save(user);
    
    return userInformation.toBean();
}

Upvotes: 1

Views: 521

Answers (2)

Giovanni
Giovanni

Reputation: 43

@maris solution worked with me as well, it seems hibernate populates the classes backwards (from child to father) I had Class A with @OneToOne relationship with class B and C, so what i´ve done is pretty similar:

// from class A:
    @OneToOne(mappedBy = "a", cascade = CascadeType.ALL,fetch = FetchType.LAZY,optional = false)
    private B b;
    
    @OneToOne(mappedBy = "a", cascade = CascadeType.ALL,fetch = FetchType.LAZY,optional = false)
    private C c;
    
// from class B:

    @OneToOne
    @MapsId
    @JoinColumn(name = "a_id")
    private A a;

//from class C:

    @OneToOne
    @MapsId
    @JoinColumn(name = "a_id")
    private A a;


    // A service class
    @Service
    public class AService {
    @Transactional
    public ADTO insert(ADTO aDTO)  {

    entityA  = modelMapper.map(aDTO, A.class);
     .
     .
     .

    // entity A is build from a DTO mapping (from POST request)

    entityB = getEntityBfromA(entityA)
    entityC = getEntityCfromA(entityA)

    entityB.setEntityA(entityA);
    entityC.setEntityA(entityA);

    entityBRepository.save(entityB);
    entityCRepository.save(entityC);

Upvotes: 0

maris
maris

Reputation: 776

After changing the below:

user = userRepository.save(user);

To:

userInformation = userInformationRepository.save(userInformation);

It works fine! Still want to know the reason and why it can't be persisted via User entity.

Upvotes: 1

Related Questions