简体   繁体   中英

Hibernate OneToOne mapped entity sets all properties to null

Using Hibernate 5, Spring 4

Please consider below codes and mapping between two entities:

User class

@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "user")
private TruckOwner truckOwner;

//getter setters below

TruckOwner class

@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id", nullable = false)
private User user;

//getter setter below

When my code tries to update values inside user class like below code: UserServiceImpl class

@Override
@Transactional(propagation = Propagation.REQUIRED, readOnly = false)
public void resetPassword(Long userId,String newPassword) {

    User user = userDAO.findById(userId);

    user.setPassword(newPassword);
    System.out.println(user.getTruckOwner().getTruckOwnerId());     
    userDAO.merge(user);
}

When calling userDAO.merge(user); I get below error: non-transient entity has a null id: com.mymodel.TruckOwner

I am facing this kind of problem in many places in my project, please help me with a proper solution to this problem and why is TruckOwner class has everything null set by hibernate?

We should know the implementation of the userdao merge method but I guess it's called the merge method of hibernate Session interface In any case the not transient object is the TruckOwner object; hibernat will not fetch the object when you call System.out.println(user.getTruckOwner().getTruckOwnerId()); moreover in that point you are out from hibernate session and if you call any other getter of truckOwner except getTruckOwnerId() you should get the org.hibernate.LazyInitializationException (or similar.. I don't remember correctly)

I guess you have 2 option:

  1. as suggested by staszko032 you should change fetch type to EAGER
  2. When you load the user object by using the userDAO.findById(userId); you should fetch the truckOwner object inside the hibernate session by calling any other method inside the userDAO.findById(userId); implementation and inside the hibernate session

I hope it's useful

Angelo

Try this for the truck class:

@Entity
@Table(name = "truckOwner")
public class TruckOwner{
...
private User user;


@OneToOne(fetch = FetchType.LAZY, mappedBy = "truckOwner", cascade = CascadeType.ALL)
public User getUser() {
    return this.user;
}
}

And this for the User class:

@Entity
@Table(name = "user")
public class User{
     private TruckOwner truckOwner;


    @OneToOne(fetch = FetchType.LAZY)
    @PrimaryKeyJoinColumn
     public TruckOwner getTruckOwner() {
          return this.truckOwner ;
     }

}

Eager mode is not a solution if you are making a production application. Problem is in your session is already closed when your are trying to getTruckOwner. Try to propagate session to all resetPassword method.

First you should not be using merge here! You should almost never use merge.

Merge should be used when you have an unmanaged entity (serialized or loaded by a previous persistence context) and wish to merge it into the current persistence context, to make it a managed entity. Your entity is already managed since a persistence context was loaded with your DAO inside a container managed transaction. This means you don't have to do even have to call save, any changed to a managed entity will be detected and persisted when the transaction commits.

On the surface JPA looks easy, because a lot of the complexity is not visible on the surface, god knows I banged my head against the wall when I started with TopLink 7 years ago, but after reading about Object life cycles and application versus container managed persistence context, I made a lot more mistakes, and it was much easier to decipher the error messages.

Another solution will be changing the fetch type to EAGER mode in User class. With LAZY mode, hibernate doesn't retrieve TruckOwner connected with user, as it is not explicitly needed in your case. Eventually TruckOwner is null for user, however it has nullable = false option set, and that's why merge fails.

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