Home > Software design >  joining multiple entities in Spring JPA
joining multiple entities in Spring JPA

Time:11-29

Have Users, Roles and User Roles tables.

Users

id
username

Roles

role_id
role_name

user_roles

user_id (fk users table)
role_id (fk roles table)

I defined my entities this way user_roles Entity

@Column(name = "USER_ID")
private int userId;

@Column(name = "ROLE_ID")
private int roleId;

@ManyToOne()
@JoinColumn(name="ROLE_ID", insertable = false, updatable = false)    
private RoleGroup userRole;

@ManyToOne()
@JoinColumn(name="id", insertable = false, updatable = false)    
private User user;

User entity:

@Id
@Column(name="ID")
@GeneratedValue(strategy = GenerationType.IDENTITY) 
private int id;
    
@Column(name = "USER_NAME")
private String userName;

Roles Entity:

@Id
@Column(name="ROLE_ID")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
    
@Column(name = "ROLE_NAME")
private String roleName;

@OneToMany(targetEntity=UserRoleGroup.class, mappedBy="userRole",cascade=CascadeType.ALL, 
    fetch = FetchType.LAZY)    
private List<UserRoleGroup> userGroup;

User table will store all lists of users. Roles table is the master table which is having 5 rows - (Admin, Read, manager..) User Role Table will have user_id from user table and role_id from roles table.

Example

USER:

id   user_name
1    test@gmail.com
2    abc@gmail.com

Roles

role_id     Name
1          Admin      
2          Manager
3          Read

User Roles

User_Id    Role_ID
1           1
1           2
2           3

Repository

@Query("FROM UserRoleGroup AS urg LEFT JOIN urg.userRole AS ur LEFT JOIN urg.user AS u WHERE u.userName = ?1") 
    public List<UserRoleGroup> findAllUserRoles(String userName);

No compilation error, no runtime error, but query isn't returning anything whereas I have data in table. when i run query in MySql I am getting data

CodePudding user response:

I was able to get this working with some minor changes to the entity classes and by adding a DTO. I think its not a good practice to pass around the entity to the client. Below is my implementation.

UserRoleGroup

@Entity
@Table@Data
public class UserRoleGroup {

    @EmbeddedId
    private UserRoleId id;

    @ManyToOne(fetch = FetchType.LAZY)
    @MapsId("userId")
    private User user;

    @ManyToOne(fetch = FetchType.LAZY)
    @MapsId("roleId")
    private Role role;
}

UserRoleId

@Embeddable
public static class UserRoleId implements Serializable {
    private static final long serialVersionUID = 1L;

    @Column(name = "user_id")
    private Integer userId;

    @Column(name = "role_id")
    private Integer roleId;

    public UserRoleId() {
    }

    public UserRoleId(Integer userId, Integer roleId) {
        super();
        this.userId = userId;
        this.roleId = roleId;
    }

    public Integer getUserId() {
        return userId;
    }

    public void setUserId(Integer userId) {
        this.userId = userId;
    }

    public Integer getRoleId() {
        return roleId;
    }

    public void setRoleId(Integer roleId) {
        this.roleId = roleId;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        UserRoleId that = (UserRoleId) o;

        if (!userId.equals(that.userId)) return false;
        return roleId.equals(that.roleId);
    }

    @Override
    public int hashCode() {
        int result = userId.hashCode();
        result = 31 * result   roleId.hashCode();
        return result;
    }
}

User


import javax.persistence.*;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;

/**
 * user can have roles
 * */

@Entity
@Table
public class User {
    @Id
    @Column(name="id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    @Column(name = "username")
    private String userName;

    @OneToMany(mappedBy = "user",
            cascade = CascadeType.ALL,
            orphanRemoval = true)
    private Set<UserRoleGroup> roles = new HashSet<>();

    public Integer getId() {
        return id;
    }

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

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public Set<UserRoleGroup> getRoles() {
        return roles;
    }

    public void setRoles(Set<UserRoleGroup> roles) {
        this.roles = roles;
    }
}

Role

import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;


@Entity
@Table(name = "roles")
public class Role {
    @Id
    @Column(name="id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    @Column(name = "role_name")
    private String roleName;

    @OneToMany(mappedBy="role",
            cascade=CascadeType.ALL,
            fetch = FetchType.LAZY)
    private List<UserRoleGroup> users = new ArrayList<>();

    public Integer getId() {
        return id;
    }

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

    public String getRoleName() {
        return roleName;
    }

    public void setRoleName(String roleName) {
        this.roleName = roleName;
    }

    public List<UserRoleGroup> getUsers() {
        return users;
    }

    public void setUsers(List<UserRoleGroup> users) {
        this.users = users;
    }
}

UserGroupRepository

import com.chait.json.generate.entity.UserRoleGroup;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public interface UserGroupRepository extends JpaRepository<UserRoleGroup,Integer> {

    @Query(
            "FROM UserRoleGroup AS urg LEFT JOIN urg.role AS ur LEFT JOIN urg.user AS u WHERE u.userName = ?1"
    )
    List<UserRoleGroup> findAllUserRoles(@Param("userName") String userName);
}

UserRoleDTO

@Data
@AllArgsConstructor
public class UserRoleDTO {
    private String username;
    private Set<String> roles;
}

UserRestController

@RestController
@RequestMapping("/users")
@RequiredArgsConstructor
public class UserRestController {

    private final UserGroupRepository userGroupRepository;

    @GetMapping("/{username}")
    public ResponseEntity<UserRoleDTO> getUserRoleByUsername(
           @PathVariable("username") String username
    ) {
        List<UserRoleGroup> userRoleGroups = userGroupRepository.findAllUserRoles(username);

        return ResponseEntity.ok(
                new UserRoleDTO(
                        userRoleGroups.get(0).getUser().getUserName(),
                        userRoleGroups
                                .stream()
                                .map(UserRoleGroup::getRole)
                                .map(Role::getRoleName)
                                .collect(Collectors.toSet())
                )
        );
    }
}
  • Related