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

I have some problem.

I have 3 tables:

users (id, name, ..)
roles (id, name)
user-role (user_id, role_id)

      

When I do a many-to-many relationship and 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 if I can only insert data into 2 tables, only (User and user_role? I have a list of roles and I shouldn't add a new role when creating a new user.

So when I do this:

SystemRole role1 = systemRoleService.findOne("ROLE_ADMIN");
userForm.setUserRole(Lists.newArrayList(role1));
....
final User saved = userRepository.save(user);
....

      

I am getting the 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 the list, add it to the user, and save the new user.

Many thanks.

+3


source to share


2 answers


@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;
}

      

+1


source


I am assuming that your code inside the userRepository.save () method is calling

entityManager.persist(user);

      

Instead, you should call



entityManager.merge(user);

      

By doing this, instead of inserting a new role, Hibernate checks to see if an existing role exists with the same identifier, and if that is the case, that role will be attached to the User object (assuming the cascading type includes a Merge operation).

The reason you need to call merge is because you are using a Role object that has been loaded (via systemRoleService.findOne ("ROLE_ADMIN")) and then detached from the persistence context, so that object detaches when you try to save user. If Role has not been disabled, you can call persist () instead of merge () on the User object.

0


source







All Articles