The issue is that the enum values are not being saved in the database, so whenever I register new user it returns user with 0 role size even though I have all the right configurations, so came to the root cause which is enum values of ERole not being saved in the database and the Role table is empty.
ERole enum:
public enum ERole {
ROLE_USER,
ROLE_MODERATOR,
ROLE_ADMIN
}
Role entity:
#EqualsAndHashCode
#NoArgsConstructor
#Getter
#Setter
#Entity
#Table(name = "roles")
public class Role implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Enumerated(EnumType.STRING)
#Column(length = 20)
private ERole role;
#ManyToMany(mappedBy="roles")
private List<User> users = new ArrayList<>();
public Role(ERole role) {
this.role = role;
}
}
User entity:
#Getter
#Setter
#NoArgsConstructor
#EqualsAndHashCode
#Entity
#Table(name = "users",
uniqueConstraints = {
#UniqueConstraint(columnNames = "name"),
})
public class User implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
private String pass;
#JsonIgnoreProperties("users")
#ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinTable(name = "user_roles",
joinColumns = { #JoinColumn(name = "user_id") },
inverseJoinColumns = { #JoinColumn(name = "role_id") })
private List<Role> roles = new ArrayList<>();
public User(String name, String pass) {
this.name = name;
this.pass = pass;
}
}
As you see below in the diagram Role entity has the role column with ERole type
I have seen the oter similar threads where it is suggested to use the #Enumerated(EnumType.STRING) which I've been using in the first place.
Related
Let's say I have this UserRole class.
It contains the roles of each user.
#Entity
#Table(name="user_roles")
public class UserRole implements Serializable{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column
private long userRoleId;
#ManyToOne
#JoinColumn(name = "user_id", foreignKey = #ForeignKey(name = "users_fk"), nullable=false)
private User user;
#ManyToOne
#JoinColumn(name = "role_id", foreignKey = #ForeignKey(name = "roles_fk"), nullable=false)
private Role role;
...
}
Now I want to have a DTO class with just userName and role that will map to the original class.
public class UserRoleRequestDTO {
private String userName;
private String role;
...
}
How do I create a mapper for that?
#Mapper
public interface UserRoleMapper {
#Mapping(//** What goes here? **//)
UserRole UserRoleRequestDTOtoUserRole(UserRoleRequestDTO userRoleRequestDTO);
}
I have a Spring Boot project, in which I have problem with JpaRepository<User,Long>.
I defined following interface
public interface UserDAO extends JpaRepository<User, Long> {
User findByEmail(String email);
}
which was implemented in UserServiceImpl
#Override
public User findByEmail(String email) {
return userDAO.findByEmail(email);
}
and I need it in UserDetailsServiceImpl but next line
User user = userDAO.findByEmail(email);
returns null.
My model classes:
User
#Entity
#Table(name = "users")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private long id;
#Column(name = "email")
private String email;
#Column(name = "login")
private String login;
#Column(name = "password")
private String password;
#ManyToMany
#JoinTable(name = "user_roles",
joinColumns = #JoinColumn(name = "user_id"),
inverseJoinColumns = #JoinColumn(name = "role_id"))
private Set<Role> roles;
#Transient
private String confirmPassword;
//getters-setters
}
Role
#Entity
#Table(name = "roles")
public class Role implements GrantedAuthority {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#Column(name = "name")
private String name;
#ManyToMany(mappedBy = "roles")
private Set<User> users;
What can I do?
You need to follow JavaBean specification for entity(you need to have default contrucor and getters and setters in User and Role)
Try to use the annotations on the getter, not the fields.
I have a OneToOne relation between tables User and Profile defined like so:
#Entity
#Builder
#Data
#NoArgsConstructor
#AllArgsConstructor
#Table(name="users", uniqueConstraints = {
#UniqueConstraint(columnNames = "username"),
#UniqueConstraint(columnNames = "email")
}
)
public class User implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int idUser;
private String username;
private String email;
private String password;
#OneToOne(cascade=CascadeType.ALL, orphanRemoval=true)
#JoinColumn(name="id_profile", referencedColumnName="idProfile")
private Profile profile;
#ManyToMany(fetch = FetchType.EAGER)
private Set<Role> roles = new LinkedHashSet<Role>();
}
#Entity
#Data
#Builder
#NoArgsConstructor
#AllArgsConstructor
#Table(name="profile",
uniqueConstraints = #UniqueConstraint(columnNames = "discordId")
)
public class Profile implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int idProfile;
private Date birthday;
private String discordId;
private String description;
#ElementCollection(fetch=FetchType.EAGER)
private Set<String> spokenLanguages = new LinkedHashSet<String>();
#OneToMany(fetch=FetchType.EAGER)
private Set<ProfileGame> profileGames = new LinkedHashSet<>();
#OneToOne(mappedBy="profile")
private User user;
#ManyToOne
private TimeSlot timeSlot;
}
Then I run a test to make some fixtures in my database:
Profile profile = this.profileRepository.save(Profile.builder()
.birthday(new Date())
.discordId("discord-" + i)
.description("Description de user-" + i)
.spokenLanguages(spokenLanguages)
.timeSlot(timeSlot)
.build());
user.setProfile(profile);
System.err.println(user);
Everything works fine here, System.err.println(user) returns correct values.
The issue comes from the database, which doesn't "apply" the id_profile in my User table:
What did I miss?
Try to do something like this:
Profile profile = Profile.builder()
.birthday(new Date())
.discordId("discord-" + i)
.description("Description de user-" + i)
.spokenLanguages(spokenLanguages)
.timeSlot(timeSlot)
.user(user)
.build();
user.setProfile(profile);
profile = this.profileRepository.save(profile);
You use a bidirectional #OneToOne association, so you should make sure both sides are in-sync at all times.
Also, as you need to propagate persistent state to the user, you should add cascade = CascadeType.ALL to the Profile.user like below:
#Entity
public class Profile implements Serializable {
// ...
#OneToOne(mappedBy="profile", cascade=CascadeType.ALL)
private User user;
}
Class User:
#OneToOne(mappedBy = "user", cascade = CascadeType.ALL,
fetch = FetchType.LAZY, optional = false)
private Profile profile;
Class Profile:
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name="id_user")
private User user;
I have 4 tables here: Register, User, User roles and User Profile Image
Register and User are mapped my a One to One relationship and a reference of Register is generated in Users table...... This is fine..
Now talking about One to Many Relation between User and the Roles table, it also works perfectly by generating a User table reference in the roles table..
But problem is when working with One to One between User and the Profile Image. Profile Image is not generating reference of User....Why the user reference is not generated in Profile Image table
Register
#Entity
#Getter
#Setter
public class Register {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#OneToOne(cascade = CascadeType.ALL,orphanRemoval = true,mappedBy = "register")
private User user;
}
User
#Entity
#Getter
#Setter
public class User {
#Id
#Column(name = "User_Id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#OneToOne(cascade = CascadeType.ALL,fetch=FetchType.EAGER)
#JoinColumn(name = "user_id")
private UserProfileImage userProfileImage;
#OneToMany(cascade = CascadeType.ALL,fetch = FetchType.EAGER)
#JoinColumn(name = "user_id")
private List<UserRoles> userRoles;
}
User Profile Image
#Entity
#Getter
#Setter
public class UserProfileImage {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(name = "name")
private String name;
#Column(name = "type")
private String type;
#Column(name = "picByte", length = 100000)
private byte[] picByte;
public UserProfileImage() {
super();
}
public UserProfileImage(String name, String type, byte[] picByte) {
this.name = name;
this.type = type;
this.picByte = picByte;
}
}
Profile mapping in User class is not correct and in your profile class there is no user field and hence it's not generating the user reference in the profile class.
Also, User to Roles mapping is also not correct, your user class will not populate roles with your mappings.
Try this:
public class User {
...
#OneToOne(cascade = CascadeType.ALL,fetch=FetchType.EAGER)
#JoinColumn(name = "PROFILE_IMAGE_ID") // foreign key column in User table
private UserProfileImage userProfileImage;
#OneToMany(cascade = CascadeType.ALL,fetch = FetchType.EAGER,mappedBy="user")
private List<UserRoles> userRoles;
}
public class UserProfileImage {
...
#OneToOne(mappedBy="userProfileImage")
private User user;
...
}
public class UserRole {
...
#ManyToOne
#JoinColumn(name="USER_ID") // foreign key column in User Role table
private User user;
...
}
I have those 3 entities that I want to transform to tables with relations
------user------
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#ToString
#Entity
#Table(name = "user")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="user_Id")
private int userId;
#Column(name="name")
private String name;
#Column(name="lastname")
private String lastname;
#Column(name="email")
private String email;
#Column(name="password")
private String password;
#Column(name="isActive")
private boolean isActive;
#Column(name="lastActive")
private String lastActive;
#Column(name="createdDate")
private String createdDate;
#Column(name="isBlocked")
private boolean isBlocked;
#ManyToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "institution_id", nullable = false)
private Institution institution;
#ManyToMany(mappedBy = "users")
private Set<Role> roles;
}
-----role------
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#ToString
#Entity
#Table(name = "role")
public class Role {
#Id
#GeneratedValue
#Column(name="role_Id")
private int roleId;
#Column(name="name")
private String name;
#Column(name="description")
private String description;
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable
private Set<User> users;
}
-----institution------
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#ToString
#Entity
#Table(name = "institution")
public class Institution {
#Id
#GeneratedValue
#Column(name="institution_Id")
private int institutionId;
#Column(name="name")
private String name;
#Column(name="type")
private String type;
#Column(name="location")
private String location;
#OneToMany(mappedBy = "institution", fetch = FetchType.LAZY)
private Set<User> user;
}
But when I run my project as a java application, no tables are created in mySQL workbench (the error occurred after adding he many-to-many annotation it was creating the tables before I add it).
Any ideas on why my code isn't working ?
And this is my application.properties
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url = jdbc:mysql://localhost:3306/mydb
spring.datasource.username = root
spring.datasource.password = pass123
spring.jpa.show-sql = true
spring.jpa.hibernate.ddl-auto = update
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect
server.port=9090
#OneToMany does not create table.
#ManyToMany creates a table, you have to specify its details, like:
In user class:
#ManyToMany
#JoinTable(name = "users_roles",
joinColumns = { #JoinColumn(name = "user_id") },
inverseJoinColumns = { #JoinColumn(name = "role_id") })
private Set<Role> roles;
In role class:
#ManyToMany(mappedBy="roles")
private Set<User> users;