Spring/Hibernate: associating from the non-owner side - java

In my system, User is the owner side of a many-to-many relationship.
User.class
#Entity
public class User {
#Id
private UUID id;
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(name = "user_rooms",
joinColumns = #JoinColumn(name = "user_id"),
inverseJoinColumns = #JoinColumn(name = "room_id"))
private Set<Room> rooms = new HashSet<>();
}
Room.class
#Entity
public class Room {
#Id
private UUID id;
#ManyToMany(mappedBy = "rooms", fetch = FetchType.LAZY)
public Set<User> users = new HashSet<>();
}
With the JSON below, I can create a User and automatically associate him with an existing Room.
Creating a User
{
"nickname":"bob",
"rooms":[{
"id":"ca6eabb6-747e-47ec-9b52-c09483f7572a"
}]
}
But when I do the same thing on the non-owner side (Room), it doesn't work. The creation is successful, but the association does not happen.
Creating a Room
{
"name":"cool_room",
"users":[{
"id":"a5744044-1e6a-4279-8731-28f1e7dfc148"
}]
}
Is it possible to associate user_rooms from the non-owner side?

Yes, it's possible, but for correct saving both side of the bidirectional association should be in-sync. So, you should correct your entities in this way:
#Entity
public class User {
#Id
private UUID id;
#ManyToMany(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE})
#JoinTable(name = "user_rooms",
joinColumns = #JoinColumn(name = "user_id"),
inverseJoinColumns = #JoinColumn(name = "room_id"))
private Set<Room> rooms = new HashSet<>();
public void addRoom(Room room) {
rooms.add( room );
room.getUsers().add( this );
}
// public void removeRoom(Room room)
// can be implemented in the similar way if it's needed
}
#Entity
public class Room {
#Id
private UUID id;
#ManyToMany(mappedBy = "rooms", fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE})
public Set<User> users = new HashSet<>();
public void addUser(User user) {
users.add( user );
user.getRooms().add( this );
}
// public void removeUser(User user)
// can be implemented in the similar way if it's needed
}
See also this part of documentation.

Related

detached entity passed to persist JPA Spring boot save

I'm triying to save a user class with company and areas selected. User has a many to many relation with company and many to many to areas.
It's giving me the error : detached entity passed to persist:
I'm not sure what is the problem
USER:
#Entity
#Table(name = "NPRO_USUARIOS")
public class User implements Serializable {
private static final long serialVersionUID = -1330075515340995797L;
#Id
#GeneratedValue(strategy=GenerationType.AUTO, generator="user_seq_gen")
#SequenceGenerator(name="user_seq_gen", sequenceName="TELCO_NPRO_USER_SEQ")
#NotNull
private int id_usuario;
#NotNull
private String nombre_usuario;
#ManyToMany(cascade = {CascadeType.PERSIST,CascadeType.REMOVE, CascadeType.MERGE, CascadeType.DETACH, CascadeType.REFRESH })
#JoinTable(name = "NPRO_USUARIOS_SOCIEDADES_AREAS", joinColumns = #JoinColumn(name = "id_usuario"), inverseJoinColumns = #JoinColumn(name = "id_sociedad"))
private Set<Sociedad> listaSociedad;
#Transient
private String sociedades;
// Si el area es nula, el usuario estara asignado a todas las areas
#ManyToMany(cascade = {CascadeType.PERSIST,CascadeType.REMOVE, CascadeType.MERGE, CascadeType.DETACH, CascadeType.REFRESH })
#JoinTable(name = "NPRO_USUARIOS_SOCIEDADES_AREAS", joinColumns = #JoinColumn(name = "id_usuario"), inverseJoinColumns = #JoinColumn(name = "id_area"))
private Set<Area> listAreas;
#Transient
private String areas;
#NotNull
private String matricula_usuario;
#NotNull
private String email_usuario;
#ManyToMany(cascade = { CascadeType.MERGE, CascadeType.DETACH, CascadeType.REFRESH })
#JoinTable(name = "NPRO_PERFILES_USUARIOS", joinColumns = #JoinColumn(name = "id_usuario"), inverseJoinColumns = #JoinColumn(name = "id_rol"))
private Set<Role> listaRoles;
#ManyToMany(cascade = { CascadeType.MERGE, CascadeType.DETACH, CascadeType.REFRESH })
#JoinTable(name = "NPRO_PERFILES_USUARIOS", joinColumns = #JoinColumn(name = "id_usuario"), inverseJoinColumns = #JoinColumn(name = "id_pantalla"))
private Set<Pantalla> listaPantallas;
private LocalDateTime fecha_ultimo_acceso;
private String observaciones;
#JsonIgnore
#ManyToOne
#JoinColumn(name = "usuario_modif")
private User usuario_modif;
}
Compnay:
#Entity
#Table(name = "NPRO_MAESTRO_SOCIEDADES")
public class Sociedad implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#NotNull
private int id_sociedad;
#NotNull
private String cod_sociedad;
#NotNull
private String cod_sociedad_gl;
#NotNull
private String nombre_sociedad;
#NotNull
private String cif_sociedad;
private String observaciones;
#JsonIgnore
#ManyToOne
#JoinColumn(name = "usuario_modif")
private User usuario_modif;
private String activo;
#JsonIgnore
#ManyToMany(cascade = {CascadeType.PERSIST,CascadeType.REMOVE, CascadeType.MERGE, CascadeType.DETACH, CascadeType.REFRESH })
#JoinTable(name = "NPRO_USUARIOS_SOCIEDADES_AREAS", joinColumns = #JoinColumn(name = "id_sociedad"), inverseJoinColumns = #JoinColumn(name = "id_usuario"))
private Set<User> listaUsuarios;
}
Area:
#Entity
#Table(name = "NPRO_MAESTRO_AREAS")
public class Area implements Serializable {
private static final long serialVersionUID = -1330075515340995797L;
#Id
#GeneratedValue(strategy=GenerationType.AUTO, generator="area_seq_gen")
#SequenceGenerator(name="area_seq_gen", sequenceName="TELCO_NPRO_AREAS_SEQ")
#NotNull
private int id_area;
#NotNull
private String nombre_area;
private LocalDateTime fecha_modif;
private String observaciones;
#JsonIgnore
#ManyToOne
#JoinColumn(name = "usuario_modif")
private User usuario_modif;
#NotNull
private String activo;
#ManyToOne
#JoinColumn(name="id_sociedad")
private Sociedad sociedad;
#JsonIgnore
#ManyToMany(cascade = {CascadeType.PERSIST,CascadeType.REMOVE, CascadeType.MERGE, CascadeType.DETACH, CascadeType.REFRESH })
#JoinTable(name = "NPRO_USUARIOS_SOCIEDADES_AREAS", joinColumns = #JoinColumn(name = "id_area"), inverseJoinColumns = #JoinColumn(name = "id_usuario"))
private Set<User> listaUsuarios;
}
I'm using springboot jpa repository save method
#Override
public User save(User user) {
return userRepository.save(user);
}
And this is the complete error :
2020-06-09 15:49:02.371 [nio-8080-exec-4] .m.m.a.ExceptionHandlerExceptionResolver : Resolved exception caused by Handler execution: org.springframework.dao.InvalidDataAccessApiUsageException: detached entity passed to persist: com.telefonica.npro.model.Area; nested exception is org.hibernate.PersistentObjectException: detached entity passed to persist: com.telefonica.npro.model.Area
Thanks in advance
EDIT :
I'm reading about the eror in this page
http://knowledgespleasure.blogspot.com/2015/06/understand-detached-entity-passed-to.html
And I guess my problem is the last one :
On the other hand, if requirement is never to add a new child if its not alredy in DB then CascadeType.PERSIST should be removed and cascade={CascadeType.MERGE,CascadeType.REFRESH} should be used
User is always related with the company and areas, and they already exist, they are not going to be new.
But if I remove PERSIST, it's triying to insert in an id null in the commun table
NPRO_USUARIOS_SOCIEDADES_AREAS
Any help ?
I will explain your problem for the #ManyToMany bidirectional relationship between User and Area entities.
A bidirectional #ManyToMany association should have an owning and a mappedBy side. The CascadeType should be present only on one side of this association.
As explained in this article, you need to have both sides in sync as otherwise, you break the Domain Model relationship consistency, and the entity state transitions are not guaranteed to work unless both sides are properly synchronized.
For this reason, the User entity defines the addArea and removeArea entity state synchronization methods.
So, you should correct your User - Area #ManyToMany mapping in this way:
#Entity
#Table(name = "NPRO_USUARIOS")
public class User implements Serializable {
// ...
#ManyToMany(cascade = {CascadeType.PERSIST,CascadeType.REMOVE, CascadeType.MERGE, CascadeType.DETACH, CascadeType.REFRESH })
#JoinTable(name = "NPRO_USUARIOS_SOCIEDADES_AREAS", joinColumns = #JoinColumn(name = "id_usuario"), inverseJoinColumns = #JoinColumn(name = "id_area"))
private Set<Area> listAreas;
public User()
{
listAreas = new HashSet<>();
}
public void addArea(Area area) {
listAreas.add(area);
area.getUsers().add(this);
}
public void removeArea(Area area) {
listAreas.remove(area);
area.getUsers().remove(this);
}
}
#Entity
#Table(name = "NPRO_MAESTRO_AREAS")
public class Area implements Serializable {
// ...
#JsonIgnore
#ManyToMany(mappedBy = "listAreas")
private Set<User> listaUsuarios;
}
And then you can save a new user in this way:
User user = new User();
// ...
Area area1 = new Area();
// ...
user.addArea(area1);
Area area2 = new Area();
// ...
user.addArea(area2);
userRepository.save(user);
The similar correction should be done for the User - Sociedad relationship.

Hibernate OneToOne relationship java.lang.NullPointerException

I'm making cart for my Spring project, I have User entity, cart and books, one user can have only one cart, so i made OneToOne relationship between user and cart, also many carts can contain many books, so i created manyToMany relationship between cart and book my code:
Book entity:
#ManyToMany
#JoinTable(
name = "books_in_cart",
joinColumns = { #JoinColumn(name = "cart_id")},
inverseJoinColumns = { #JoinColumn(name = "book_id")}
)
private Set<Cart> inCarts = new HashSet<>();
Cart entity:
#Entity
public class Cart {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#OneToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "idUsers")
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
#ManyToMany
#JoinTable(
name = "books_in_cart",
joinColumns = { #JoinColumn(name = "book_id")},
inverseJoinColumns = { #JoinColumn(name = "cart_id")}
)
private Set<Book> books = new HashSet<>();
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Set<Book> getBooks() {
return books;
}
public void setBooks(Set<Book> books) {
this.books = books;
}
}
and User entity
#OneToOne(mappedBy = "user",cascade = CascadeType.MERGE,fetch = FetchType.EAGER,orphanRemoval = true)
private Cart userCart = new Cart();
Code that I use to add book to user's cart:
#PostMapping(value = "/addToCart")
#Secured("USER")
public String addToCart(#RequestParam(name = "ids") int id,Principal principal){
System.out.println(principal.getName());
User login = userDao.getByLogin(principal.getName());
Book book = service.getById(id);
login.getUserCart().setUser(login);
login.getUserCart().getBooks().add(book);
userDao.save(login);
return "redirect:/books";
}
I'm getting this exception :
java.lang.NullPointerException
controller.libraryController.addToCart(libraryController.java:170)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
The mapping is definitely wrong, probably the whole model is, because it look like you don't have a joining table at all:
joinColumns = { #JoinColumn(name = "cart_id")},
inverseJoinColumns = { #JoinColumn(name = "book_id")}
This means, that one entity has an id named cart_id in one table and book_id in the other one, which doesn't make any sense. That is why the exception is thrown.
You need to fix your model, both database and mapping. Here's a good read about it.

JPA + Hibernate mapping java.util.Set in one Entity to another Entity java.util.Map

I'm having a problem with JPA + Hibernate mapping in my project(I'm a total newbie to hibernate and jpa so please, be patient :) ).
Here are my entities:
#Entity
#Table(name = "yeasts")
public class Yeast {
...
private Set<BeerRecipe> recipes;
...
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(name = "recipe_yeasts"
,joinColumns = #JoinColumn(name = "yst_id", referencedColumnName = "yst_id")
,inverseJoinColumns = #JoinColumn(name = "brp_id", referencedColumnName = "brp_id"))
public Set<BeerRecipe> getRecipes() {
return recipes;
}
public void setRecipes(Set<BeerRecipe> recipes) {
this.recipes = recipes;
}
}
and the second one:
#Entity
#Table(name = "beer_recipes")
public class BeerRecipe {
...
private Map<Yeast,Double> yeasts;
...
#ManyToMany(cascade = CascadeType.ALL)
#ElementCollection
#JoinTable(name = "recipe_yeasts"
,inverseJoinColumns = #JoinColumn(name = "yst_id", referencedColumnName = "yst_id")
,joinColumns = #JoinColumn(name = "brp_id", referencedColumnName = "brp_id"))
public Map<Yeast, Double> getYeasts() {
return yeasts;
}
public void setYeasts(Map<Yeast, Double> yeasts) {
this.yeasts = yeasts;
}
...
}
I'm stuck here, because I can't find a solution to my problem. I need my BeerRecipe objects to store a Map< Yeast,Double> (double stands for amount of yeasts used in beer recipe), and Yeast objects to store Set< BeerRecipe>(many to many relationship - X beer recipes using the same yeasts and X yeasts being used in the same recipe)
Right now I'm getting an exception:
Use of #OneToMany or #ManyToMany targeting an unmapped class:
my.project.db_model.BeerRecipe.yeasts[java.lang.Double]
An example solution:
#Entity
#Table(name = "yeasts")
public class Yeast {
#Id
private int yst_id;
#OneToMany(cascade=CascadeType.ALL, mappedBy="yeasts")
private Set<BeerRecipe> recipes;
...
}
#Entity
#Table(name = "beer_recipes")
public class BeerRecipe {
#Id
private int brd_id;
#ElementCollection
#CollectionTable(name = "recipe_yeasts", joinColumns = #JoinColumn(name = "brd_id"))
#MapKeyJoinColumn(name = "yst_id", referencedColumnName = "yst_id") //refers to Yeast
#Column(name = "amount") //refers to Double
private Map<Yeast, Double> yeasts;
...
}
With such approach you preserve bidirectional relationship between beer_recipes and yeast. The map stands for recipe_yeasts join table in between.

Hibernate two parents one child mapping

I have following scenario: There are companies and employees. Each company has a set of employees. Each employee can work for several companies. So I implemented following relationships:
Company.class:
#JoinTable(name = "company_employee", joinColumns = #JoinColumn(name = "company_id") , inverseJoinColumns = #JoinColumn(name = "employee_id") )
#ManyToMany(fetch = FetchType.LAZY)
private List<Employee> employees;
Employee.class:
#JoinTable(name = "company_employee", joinColumns = #JoinColumn(name = "employee_id") , inverseJoinColumns = #JoinColumn(name = "company_id") )
#ManyToMany(fetch = FetchType.LAZY)
private List<Company> companies;
Obviously, to work for several companies, each employee should have several not overlapping schedules assigned for each company he or she works.
Also, there should be a list of schedules for each combination Company-Employee, as sometimes old schedule expires, and new schedule becomes effective.
So I also have Schedule.class, which is supposed to have child to parent #ManyToOne relationships both to Company and Employee, and should work following way: each Schedule, and thus, List<Schedule> should correspond to exactly one combination of Company and Employee instances.
How to implement this relationship?
Update 1
I only have in mind adding #OneToMany Schedule relationship to each Company and Employee, but then I need to put instances of Schedule both to Company and Employee each time, and this way just don't look right, also it's not obvious for me now how to fetch it back.
So any help will be appreciated.
This post was updated to show real-life scenario I have, not just generic Entity1, Entity2, Entity3 names for classes.
Update 2
I accepted the answer, but I cannot use it if Schedule contain Lists.
According to my plan, Schedule should contain List<Vacation> to know the set of Vacations over a year, and List of Days, each of which shows start of particular week day, break, and end of this day. Those Days are also unique for each Schedule instance.
It was supposed to be something like below, but obviously now I don't have schedule_id, so how to connect those lists to Schedule?
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
#JoinColumn(name = "schedule_id")
private List<Vacation> vacations;
#JoinTable(name = "schedule_week", joinColumns = #JoinColumn(name = "schedule_id") , inverseJoinColumns = #JoinColumn(name = "day_id") )
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
private List<Day> week;
How to include those lists right?
I would like to suggest the following solution.
An embeddable class that contains the Company and Employee for a particular schedule.
#Embeddable
public class ScheduleOwner implements Serializable{
#MapsId("id")
#ManyToOne(cascade = CascadeType.ALL)
Company c;
#MapsId("id")
#ManyToOne(cascade = CascadeType.ALL)
Employee e;
}
The Schedule class is embedding a ScheduleOwner instance.
#Entity
public class Schedule {
#EmbeddedId
ScheduleOwner owner;
String description;
}
The Company and Employee classes(no change done to them)
#Entity
public class Company {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#JoinTable(name = "company_employee", joinColumns = #JoinColumn(name = "company_id") , inverseJoinColumns = #JoinColumn(name = "employee_id") )
#ManyToMany(fetch = FetchType.LAZY)
private List<Employee> employees;
}
#Entity
public class Employee {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#JoinTable(name = "company_employee", joinColumns = #JoinColumn(name = "employee_id") , inverseJoinColumns = #JoinColumn(name = "company_id") )
#ManyToMany(fetch = FetchType.LAZY)
private List<Company> companies;
}
UPDATE 1
Below is how you could save and fetch results.
Employee e1 = new Employee();
Company c1 = new Company();
c1.employees.add(e1);
e1.companies.add(c1);
ScheduleOwner so = new ScheduleOwner();
so.c = c1;
so.e = e1;
Schedule s = new Schedule();
s.owner = so;
session.save(c1);
session.save(e1);
session.save(s);
// below query will fetch from schedule, where company id = 9
Schedule ss = (Schedule) session.createQuery("From Schedule sh where sh.owner.c.id = 9").uniqueResult();
UPDATE 2
#Entity
public class Company {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#JoinTable(name = "company_employee", joinColumns = #JoinColumn(name = "company_id", referencedColumnName="id")
, inverseJoinColumns = #JoinColumn(name = "employee_id", referencedColumnName="id"))
#ManyToMany(fetch = FetchType.LAZY)
List<Employee> employees = new ArrayList<>();
String name;
}
#Entity
public class Employee {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#ManyToMany(fetch = FetchType.LAZY, mappedBy = "employees")
List<Company> companies = new ArrayList<>();
String name;
}
#Entity
public class Schedule {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
int schedule_id;
#ManyToOne
#JoinColumn(name = "company_id", insertable = false, updatable = false)
private Company company;
#ManyToOne
#JoinColumn(name = "employee_id", insertable = false, updatable = false)
private Employee employee;
String description;
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "schedule")
List<Vacation> vacations;
}
#Entity
public class Vacation {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int vacation_id;
#ManyToOne
#JoinColumn(name = "schedule_id" )
Schedule schedule;
#OneToMany(mappedBy = "vacation")
List<Day> days;
}
Day entity directly relates to Vacation. Not to Schedule.
#Entity
public class Day {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#ManyToOne
#JoinColumn(name = "vacation_id")
Vacation vacation;
}
Hope this helps.

Jpa many-to-many how can I insert data into 2 tables only

I have a some problem.
I have 3 tables:
users (id, name, ..)
roles (id, name)
user-role (user_id, role_id)
When I do many-to-many relationship and do save() I have 3 inserts.
User:
#Entity
#Table(name = "user")
public class User implements Serializable {
public static final String UK_EMAIL = "uk_email";
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#ManyToMany(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE})
#JoinTable(
name = "system_user_role",
joinColumns = {#JoinColumn(name = "user_id", referencedColumnName = "id")},
inverseJoinColumns = {#JoinColumn(name = "role_id", referencedColumnName = id")}
)
private List<SystemRole> userRole;
public List<SystemRole> getUserRole() {
return userRole;
}
SystemRole;
#Entity
#Table(name = "system_role")
public class SystemRole implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column
private String name;
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(
name = "system_user_role",
joinColumns = {#JoinColumn(name = "role_id", referencedColumnName = "id")},
inverseJoinColumns = {#JoinColumn(name = "user_id", referencedColumnName = "id")}
)
private List<User> users;
public List<User> getUsers() {
return users;
}
public void setUsers(List<User> users) {
this.users = users;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
PLEASE, tell me, can I insert data into 2 tables only, only into (User and user_role?
I have roles list and I need not add a new role when I create a new user.
So, when I do:
SystemRole role1 = systemRoleService.findOne("ROLE_ADMIN");
userForm.setUserRole(Lists.newArrayList(role1));
....
final User saved = userRepository.save(user);
....
I get an error:
org.springframework.dao.InvalidDataAccessApiUsageException: detached entity passed to persist:...
If i do:
#Service("userService")
#Transactional
public class UserServiceImpl implements UserDetailsService, ResourceService<User> {
private final static Logger LOGGER = LoggerFactory.getLogger(UserServiceImpl.class);
#Autowired
private UserDAO userRepository;
#Autowired
private SystemRoleDAO systemRoleRepository;
#Override
#Transactional(rollbackFor = ResourceException.class)
public User create(User user) throws ResourceException {
try {
SystemRole role1 = systemRoleRepository.findOne(6l);
user.setUserRole(Lists.newArrayList(role1));
user.setId(62l); // !!! if set user ID - it works CORRECT
final User saved = userRepository.save(user);
return saved;
} catch (DataIntegrityViolationException ex) {
...
UserDAO:
#Repository
public interface UserDAO extends JpaRepository<User, Long> {
...
SystemRoleDAO:
#Repository
public interface SystemRoleDAO extends JpaRepository<SystemRole, Long> {
It works, but I have 3 inserts.
When I create a new user, I need to select a role from list, add it to the user and save the new user.
Many thanks.
#Entity
#Table(name = "user")
public class User implements Serializable {
public static final String UK_EMAIL = "uk_email";
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#ManyToMany(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE}) //Make CascadeType.Detached this should solver your problem
#JoinTable(
name = "system_user_role",
joinColumns = {#JoinColumn(name = "user_id", referencedColumnName = "id")},
inverseJoinColumns = {#JoinColumn(name = "role_id", referencedColumnName = id")}
)
private List<SystemRole> userRole;
public List<SystemRole> getUserRole() {
return userRole;
}
I guess that your code inside the userRepository.save() method is calling
entityManager.persist(user);
Instead you should be calling
entityManager.merge(user);
BY doing so, instead of inserting a new Role, Hibernate will check if a Role with the same ID already exists and if this is case, that Role will be attached to the User entity (provided that the cascade type includes Merge operation).
The reason why you need to call merge is that you are using a Role entity which has been loaded (via systemRoleService.findOne("ROLE_ADMIN")) and then detached from persistence context, so this entity is detached when you try to save the User. If Role had not been detached, you could call persist() instead of merge() on the User entity.

Categories

Resources