0

I have problem with JPA provided by Hibernate. Here are my entities:

@Entity
public class Action {
    @Id
    @GeneratedValue
    private Integer id;

    @Column
    private String name;

    @JoinColumn
    @ManyToOne
    private User user;

    public Integer getId() { return this.id; }
    protected void setId(Integer id) { this.id = id; }

    public String getName() { return this.name; }
    public void setName(String name) { this.name = name; }

    public void getUser() { return this.user; }
    protected void setUser(User user) { this.user = user; }
}
@Entity
public class User {
    @Id
    @GeneratedValue
    private Integer id;

    @Column
    private String name;

    @OneTomany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    private List<Action> actions = new ArrayList<>();

    public Integer getId() { return this.id; }
    protected void setId(Integer id) { this.id = id; }

    public String getName() { return this.name; }
    public void setName(String name) { this.name = name; }

    public void addAction(Action action) {
        action.setUser(this);
        actions.add(action);
    }
    public void removeAction(Action action) {
        actions.remove(action);
        action.setUser(null);
    }
    public List<Action> getActions() { return Collections.unmodifiableList(actions); }
}

Here is my controller code:

@Controller
@RequestMapping("/user/{username}")
@SessionAttributes("user")
public class ActionController {
    @Autowired
    private TestService service;

    @ModelAttribute("user")
    public User contextRegistration(@PathVariable("username") String username) {
        return this.service.getByName(username);
    }

    @RequestMapping("")
    public String userView() {
        return "user";
    }

    @RequestMapping(value = "/add", method = RequestMethod.GET)
    public String addAction(@ModelAttribute Action action) {
        return "addAction";
    }

    @RequestMapping(value = "/add", method = RequestMethod.POST)
    public String postAddAction(@Valid Action action, BindingResult result, User user, SessionStatus sessionStatus) {
        if(result.hasErrors()) {
            return "addAction";
        }

        user.addAction(action);
        this.service.saveAction(action);
        sessionStatus.setComplete();
        return "redirect:/user/{username}";
    }
}

When method postAddAction is executed I got the following error:

org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing : pl.zaprogramowany.test.model.Action.user -> pl.zaprogramowany.test.model.User

in line where method saveAction is executed.

My code is modeled on this code https://github.com/spring-projects/spring-petclinic/blob/master/src/main/java/org/springframework/samples/petclinic/web/PetController.java#L79 but I don't know why I have this error because my code is pretty similar to this.

Can anybody help?

@Edit

I'm using spring Jpa repositories and code in service layer is very simple.

@Transactional(readyOnly = true)
public User getByName(String name) {
    return this.userRepository.getByName(name);
}

@Transactional
public void saveAction(Action action) {
    this.actionRepository.save(action);
}
Zaprogramowany
  • 623
  • 1
  • 7
  • 10

2 Answers2

1

This problem arises when you dont include cascade="all" (if using xml) or cascade=CascadeType.ALL (if using annotations) on your collection mapping.

Which in your case exists but at the user entity but not at the action entity

hence we need to see how are we saving the action entity on the basis of which we can decide if we need to add cascade on action entity or not

Mudassar
  • 3,135
  • 17
  • 22
0

Your EntityManager is not aware of the User instance that is injected in your method. Then, when you try to save the Action instance with a reference to unaware User instace you get the transient object exception.

I don't know exactly how your User instance is injected but with that instance you should use entity manager to find it from the database. Doing this, your entity manager is aware of which user you are trying to use. Take a look to this post

Community
  • 1
  • 1
theBittor
  • 786
  • 1
  • 11
  • 20
  • User instance comes from contextRegistration and It's being saved as session attribute. When spring call to postAddAction method It is injected to method from session. Here it was described http://stackoverflow.com/questions/3423262/what-is-modelattribute-in-spring-mvc – Zaprogramowany Jun 25 '15 at 15:35
  • Good. But Jpa does not know that object, is not in jps session. Try to look up the user with the entity manager and add that instance to your action – theBittor Jun 25 '15 at 17:09
  • It doesn't work. Take a look here https://github.com/spring-projects/spring-petclinic/blob/master/src/main/java/org/springframework/samples/petclinic/service/ClinicServiceImpl.java#L66 – Zaprogramowany Jun 25 '15 at 21:51