Reputation: 98
I have an problem with saving Many-To-One Field in Spring Data JPA. Consider Entity User and Group as shortly described below :
@Entity
@Table(name = "Users")
public class User {
@Basic(optional = false)
@Column(name = "username")
private String username;
@JoinColumn(name = "group_id", referencedColumnName = "id")
@ManyToOne
private Group group;
}
@Entity
@Table(name = "groups")
public class Group {
@Basic(optional = false)
@Column(name = "name")
private String name;
@OneToMany(mappedBy = "group",cascade=CascadeType.PERSIST)
private Collection<User> userCollection;
}
when i want to Update User Entity and change its group with CrudRepository save method following exception occured : org.hibernate.HibernateException: identifier of an instance of Group was altered from 2 to 1 and that shows spring data want to edit Group's id field while it is not corrent and i want to change reference of it not its id.
For Update i get view data in a DTO form and after that i convert dto object to entity object using Dozer Mapper as described below:
DozerBeanMapper mapper = new DozerBeanMapper();
// get user by id from database for editing
User user = this.userService.findByIdAndDeletedFalse(form.getId());
// merge view data and entity data using Dozer
mapper.map(form, user);
// save User entity
this.userService.save(user);
userService is a bean that call crudRepository save method only.
Any Solution?
Thanks
Upvotes: 4
Views: 6099
Reputation: 603
It's because you are using a transient Group. You need to fetch your group and then assign the group to your user object.
Upvotes: 0
Reputation: 5025
I think you should tell Dozer
to exclude group
field using the following xml.
<field-exclude>
<a>group</a>
</field-exclude>
And the set the group
manually.
mapper.map(form, user);
user.setGroup(this.groupService.finfById(form.group.getId()));
// save User entity
this.userService.save(user);
If you don't want to map the group in your controller. You could use a DozerConverter
class where you can fetch the group
object and set it there.
<mapping>
<class-a>org.mypackage.Form</class-a>
<class-b>org.mypackage.User</class-b>
<field custom-converter-id="org.mypackage.UserGroupCustomConverter">
<a>groupId</a>
<b>group</b>
</field>
</mapping>
public class UserGroupCustomConverter extends DozerConverter<Form, User> {
public NewDozerConverter() {
super(Form.class, User.class);
}
public Boolean convertTo(Form form, User user) {
user.setGroup(this.groupService.finfById(form.group.getId()));
}
}
Upvotes: 0
Reputation: 10716
The error occurs because you are trying to change the id
of a tracked entity, which is not allowed in JPA. You need to obtain a reference to the new Group
and assign it to User.group
.
In short, instead of this:
user.getGroup().setId(newId);
Try this:
user.setGroup(entityManager.getReference(Group.class, newId));
Upvotes: 2