简体   繁体   中英

JPA: redundant sql insertions after using multiple many-to-many relations between three entities

I have User, Role and Permission entities and use embedded db for development purpose. User and Role have many-to-many relation and, also, Role and Permission have many-to-many relation too: 1) User entity:

@Entity
@Table(name = "usr")
@JsonIgnoreProperties(ignoreUnknown = true)
public class User implements Serializable {

    private static final long serialVersionUID = 818129969599480161L;
    /**
     * Unique id for the User. "@Id" declare the parameter as the primary key
     * "@GeneratedValue" indicates JPA 2 (and behind Hibernate) which strategy
     * to use for creating a new value.
     * "GenerationType.AUTO" value allow JPA implementation to use the better way depending to the RDBMS used.
     */
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;
    /**
     * Login of the user. No annotation here, the parameter will be automatically mapped in the table.
     */
    private String login;
    /**
     * Password of the user. No annotation here, the parameter will be automatically mapped in the table.
     */
    private String password;

    @ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @JoinTable(name = "USER_ROLES",
            joinColumns =
            @JoinColumn(name = "user_id"),
            inverseJoinColumns =
            @JoinColumn(name = "role_id"))
    private Set<Role> roles = new HashSet<>();
.....(getters and setters)

2) Role entity:

@Entity
public class Role {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int id;
    private String roleName;

    @ManyToMany(mappedBy = "roles", fetch=FetchType.EAGER)
    private Set<User> users = new HashSet<>();

    @ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @JoinTable(name = "ROLE_PERMISSION",
            joinColumns =
            @JoinColumn(name = "ROLE_ID"),
            inverseJoinColumns =
            @JoinColumn(name = "PERMISSION_ID"))
    private Set<Permission> permissions = new HashSet<>();
    .....(getters and setters)

3) Permisson entity:

    @Entity
    public class Permission {
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        private int id;
        private String permissionName;

        @ManyToMany(mappedBy = "permissions", fetch=FetchType.EAGER, cascade = {})
        private Set<Role> roles = new HashSet<>();
    .....(getters and setters)

And offcause my test populator:

public void afterPropertiesSet() throws Exception {
    _logger.debug("setting test uses data");

    Permission permission = new Permission();
    permission.setPermissionName("PERM_SAVE_PRODUCT");

    permissionRepository.save(permission);

    Role role = new Role();
    role.setRoleName("ROLE_ADMIN");
    Set<Permission> permissions = new HashSet<>();
    permissions.add(permission);
    role.setPermissions(permissions);

    roleRepository.save(role);

    User user = new User();
    user.setLogin("dmitro");
    user.setPassword("2424");
    user.setStatus(UserStatus.ACTIVE);
    Set<Role> roles = new HashSet<Role>();
    roles.add(role);
    user.setRoles(roles);

    userRepository.save(user);
}

I expected that one user record, one role record and one permission record are created and inserted into particulars repos. All seems to be clean (without any exception) but rest clien show me that I have two role records and three permission records, for role for example:

{
"links": [
],
"content": [
    {
        "links": [
            {
                "rel": "roles.Role.permissions",
                "href": "http://localhost:8080/admin/roles/1/permissions"
            },
            {
                "rel": "self",
                "href": "http://localhost:8080/admin/roles/1"
            },
            {
                "rel": "roles.Role.users",
                "href": "http://localhost:8080/admin/roles/1/users"
            }
        ],
        "roleName": "ROLE_ADMIN"
    },
    {
        "links": [
            {
                "rel": "roles.Role.permissions",
                "href": "http://localhost:8080/admin/roles/2/permissions"
            },
            {
                "rel": "self",
                "href": "http://localhost:8080/admin/roles/2"
            },
            {
                "rel": "roles.Role.users",
                "href": "http://localhost:8080/admin/roles/2/users"
            }
        ],
        "roleName": "ROLE_ADMIN"
    }
],
"page": {
    "size": 20,
    "totalElements": 2,
    "totalPages": 1,
    "number": 1
}

}

In log I see that it is all created but why in such way I do not know yet, please help. log is here: https://www.dropbox.com/s/orx3c9p023bxmti/log.txt?dl=0

You are saving user ,Role , permission separately . This will result multiple records . Since you have given Cascade All saving User Object will save role objects and permission objects too.

try like this

public void afterPropertiesSet() throws Exception {
_logger.debug("setting test uses data");

User user = new User();
user.setLogin("dmitro");
user.setPassword("2424");
user.setStatus(UserStatus.ACTIVE);
Set<Role> roles = new HashSet<Role>();
Role role = new Role();
role.setRoleName("ROLE_ADMIN");
Set<Permission> permissions = new HashSet<>();
Permission permission = new Permission();
permission.setPermissionName("PERM_SAVE_PRODUCT");
permissions.add(permission);
role.setPermissions(permissions);
roles.add(role);
user.setRoles(roles);
userRepository.save(user);

}

See about cascade here . Hope it helps

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM