I'm making a basic user registration in Spring Boot and I use the #Column(unique = true) annotation but it isn't working. I can register multiple user with the same email.
Here is my code:
package io.agile.ppmtool.domain;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import javax.persistence.*;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import java.util.Collection;
import java.util.Date;
#Entity #Getter #Setter #NoArgsConstructor
public class User implements UserDetails {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Email(message = "Username needs to be an email")
#NotBlank(message = "username is required")
#Column(unique = true)
private String username;
#NotBlank(message = "Please enter your full name")
private String fullName;
#NotBlank(message = "Password field is required")
private String password;
#Transient
private String confirmPassword;
private Date created_At;
private Date updated_At;
}
I hope somebody can help me why this annotation don't work for me.
unique in #Column is used only if you let your JPA provider create the database for you - it will create the unique constraint on the specified column.
But if you already have the database, or you alter it once created, then unique doesn't have any effect.
So you need the unique constraint in the database somehow, having only the #Column is no guarantee.
Related
I am using JPA + Spring Boot for my project. This is the first time I'm using JPA and I'm also very new to Spring Boot.
I want to create two tables file_perms and file_perm_values. I am able to get the definition of file_perms right. However, for my second table file_perm_values, I want to define a composite primary key that consists of the primary key of the file_perms, i.e., id and another String file_id. When I write the definition shown below and use the DDL creation button of Intellij, I get the error Caused by: java.lang.IllegalStateException: The column type is undefined. Table - file_perm_values; Column - file_perm_id
What am I doing wrong?
Could some of the experts out there please help me understand what's the problem and how to fix this?
I'll be very grateful
package com.some.project.persistence.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import java.time.ZonedDateTime;
import java.util.UUID;
#Entity
#Getter
#Builder
#NoArgsConstructor
#AllArgsConstructor
#ToString(onlyExplicitlyIncluded = true)
#Table(name = "file_perms")
public class FilePermsEntity {
#Id
#GeneratedValue
#Builder.Default
#ToString.Include
#Column(name = "id", nullable = false)
private UUID id = null;
#ToString.Include
#Column(name = "perm_name", nullable = false)
private String permName;
#ToString.Include
#Column(name = "is_active", nullable = false)
private boolean active;
#ToString.Include
#Column(name = "perm_guid")
private String permGuid;
#ToString.Include
#Column(name = "perm_index")
private int permIndex;
#CreatedDate
#Builder.Default
#ToString.Include
#Column(name = "created_at")
private ZonedDateTime createdAt = ZonedDateTime.now();
#Builder.Default
#ToString.Include
#LastModifiedDate
#Column(name = "updated_at")
private ZonedDateTime updatedAt = ZonedDateTime.now();
}
package com.some.project.persistence.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import javax.persistence.Column;
import javax.persistence.Embeddable;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.MapsId;
import javax.persistence.Table;
import java.io.Serializable;
#Entity
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#Builder
#ToString(onlyExplicitlyIncluded = true)
#Table(name = "file_perm_values")
public class FilePermValuesEntity {
#EmbeddedId
#ToString.Include
private FilePermValuesPrimaryKey id;
#ToString.Include
#Column(name = "value")
private String value;
#Getter
#Builder
#Embeddable
#NoArgsConstructor
#AllArgsConstructor
#ToString(onlyExplicitlyIncluded = true)
public static class FilePermValuesPrimaryKey implements Serializable {
private static final long serialVersionUID = 1223232L;
#MapsId
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "file_perm_id", nullable = false)
private FilePermsEntity filePermsEntity;
#ToString.Include
#Column(name = "file_id", nullable = false)
private String fileId;
#Override
public boolean equals(Object o) {
...
}
#Override
public int hashCode() {
...
}
}
}
The code below solved my problem:
#Entity
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#Builder
#ToString(onlyExplicitlyIncluded = true)
#Table(name = "file_perm_values")
public class FilePermValuesEntity {
#EmbeddedId
#ToString.Include
private FilePermValuesPrimaryKey id;
#MapsId("filePermId")
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "file_perm_id")
private FilePermsEntity filePermsEntity;
#ToString.Include
#Column(name = "value")
private String value;
#Getter
#Builder
#Embeddable
#NoArgsConstructor
#AllArgsConstructor
#ToString(onlyExplicitlyIncluded = true)
public static class FilePermValuesPrimaryKey implements Serializable {
private static final long serialVersionUID = 1223232L;
#ToString.Include
#Column(name = "file_perm_id", nullable = false)
private UUID filePermId;
#ToString.Include
#Column(name = "file_id", nullable = false)
private String fileId;
#Override
public boolean equals(Object o) {
...
}
#Override
public int hashCode() {
...
}
}
}
I have the following code, where I need to populate a set with multiple objects that are instances of the same class (User). The problem is, I only get the first object when I log.
user = User.builder()
.id(1L)
.username("2397047")
.nickname("test1")
.build();
anotherUser = User.builder()
.id(2L)
.username("23971948")
.nickname("test2")
.build();
Set<User> userSet = new HashSet<>();
userSet.add(user);
userSet.add(anotherUser);
System.out.println("User set from test " + userSet);
This code produces the following output
User set from test [User(id=1, nickname=test1, username= 2397047, password=null, roles=null, groups=null)]
Why am I unable to get the entire collection?
This is my User class
package com.chama.chamaservice.user;
import com.chama.chamaservice.BaseEntity;
import com.chama.chamaservice.Views;
import com.chama.chamaservice.config.ApplicationUserRole;
import com.chama.chamaservice.group.Group;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonView;
import lombok.*;
import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;
#Builder
#Entity
#NoArgsConstructor
#AllArgsConstructor
#Getter
#Setter
#ToString
public class User extends BaseEntity {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#JsonView(Views.Public.class)
private Long id;
#JsonView(Views.Public.class)
private String nickname;
#JsonView(Views.Public.class)
private String username; // <- Unique user's phone number
private String password;
#ElementCollection(targetClass = ApplicationUserRole.class)
#CollectionTable(name = "user_role", joinColumns = #JoinColumn(name = "user_id"))
#Enumerated(EnumType.STRING)
#Column(name = "role")
private Set<ApplicationUserRole> roles;
#JsonIgnore
#ManyToMany(mappedBy = "groupMembers", fetch = FetchType.LAZY, targetEntity = Group.class)
private Set<Group> groups = new HashSet<>();
}
In the User class, #Data annotation which will implement #Getter, #Setter, #ToString method.
It will print all values in the Set.
Found an answer, although it may not be the optimal solution. I annotated the User class with #EqualsAndHashCode
I have problem with adding users role during registration request
This is my DB diagram:
And I have the following classes: first is entity role:
package application.model;
import lombok.*;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import javax.persistence.*;
import java.util.List;
#NamedQueries({
#NamedQuery(name = User.GET_USERS, query = User.QUERY_GET_USERS),
})
#Getter
#Setter
#NoArgsConstructor
#Entity
#Table(name = "users")
public class User {
public static final String GET_USERS = "User.get_users";
public static final String QUERY_GET_USERS = "select u from User u";
#Id
#NotNull
#GeneratedValue(strategy = GenerationType.SEQUENCE)
#Column(name = "id")
public int id;
#NotNull
#NotEmpty
#Column(name="firstname")
private String firstname;
#NotNull
#Column(name="lastname")
private String lastname;
#NotNull
#Column(name="email")
private String email;
#NotNull
#Column(name="password")
private String password;
#JoinTable
#OneToMany
private List<Role> roles;
}
second entity is Role:
package application.model;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import javax.persistence.*;
import javax.validation.constraints.NotNull;
#Getter
#Setter
#NoArgsConstructor
#Entity
#Table(name = "role")
public class Role {
#Id
#NotNull
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
public int id;
#NotNull
#Column(name="name")
private String name;
}
So, i have 3 roles in my application, when I register new user with post request:
{
"firstname": "imasdie5",
"lastname": "nazasdwisko5",
"email": "masdil",
"password": "pass",
"roles": [
{ "id":2 }
]
}
First user is registered correctly, but when i send second request with same roles.id=2, i have:
ERROR: duplicate key value violates unique constraint "uk_d9najy24fium4vkivgwjuf0hw"
Detail: Key (roles_id)=(2) already exists.
In dbeaver table users_role have constraint uk_d9najy24fium4vkivgwjuf0hw with type UNIQUE_KEY, so that's the problem, but how to change type to non-unique? Many users may have same role, so it is necessary for me
All tables are generated with hibernate.
Table users_role is not entity in my application, maybe it should be entity?
Do You have any advice what I should change to add one role for many users?
Try to use #ManyToMany annotation
#JoinTable
#ManyToMany
private List<Role> roles;
I want to generate User object using Thymeleaf template. How can I do this? I have an User class containing information as follow.
package com.rhv.um.model;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
import javax.persistence.Transient;
#Entity
#Table(name = "users")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "firstname")
private String firstName;
#Column(name = "lastname")
private String lastName;
#Column(name = "email")
private String email;
#Column(name = "mobile")
private Long mobile;
#Column(name = "username")
private String username;
#Column(name = "password")
private String password;
#Transient
private String confirmPassword;
#Column(name = "isenable", columnDefinition = "boolean default 1")
private boolean isEnable;
#Column(name = "reason")
private String reason;
#ManyToMany
#JoinTable(name = "users_roles", joinColumns = #JoinColumn(name = "user_id"), inverseJoinColumns = #JoinColumn(name = "roles_id"))
private Set<Role> roles;
//Getter and Setter
}
I have an UserRepository class and UserService class too. UserService class is as follow. UserRepository class is same as UserService class
package com.rhv.um.service;
import java.util.List;
import com.rhv.um.model.User;
public interface UserService {
void save(User user, boolean updatePassword);
List<User> findAll();
User findByUsername(String username);
}
Now I want to create an object of User from thymeleaf by using findByUsername(String username) method of UserService class. I want to get the details of currently logged-in user from this.
As I am using SpringSecurity5. I can get currently logged in user from thymeleaf as below.
<span th:text="${#authentication.getPrincipal().getUsername()}"></span>
I want to pass this username to my methods and get the User object. Not only the currently logged-in user. I do need to get User object of other users in the system.
I know few ways of doing it as below.
Setting the values of currently logged-in user in cookie and fetch it from UI.
Setting the values of currently logged-in user in session and fetch from UI.
Setting the User object to model attribute and then use the object from UI.
Using above ways, My purpose is getting solved. But I want to set object from thymeleaf. How can I do it?
I had tried by using th:with of thymeleaf. It didn't worked for me
<div th:if="${userCredentials == null}" th:with="userCredentials=${T(your.package.here.UserCredentials).create()}"></div>
Post for above line of code is here
Please let me know if more information is needed. Also guide me with the code if I am doing anything wrong here.
The problem is that when i run the application hibernate creates a column user_id in the tahograph_cards table which i don't want and it doesn't create a column tahograph_card_id in the users table which I want to.
It's a OneToMany relationship.
Here are my files:
application.properties:
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/getmydrivercard
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.jpa.generate-ddl=true
spring.jpa.hibernate.ddl-auto = update
User:
package com.getmydrivercard.getmydrivercard.models;
import com.fasterxml.jackson.annotation.JsonIgnore;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.OnDelete;
import org.hibernate.annotations.OnDeleteAction;
import javax.persistence.*;
import javax.validation.constraints.NotEmpty;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
#Entity
#Table(name = "users")
public class User {
private static final String EMPTY_STRING = "";
#Id
#GeneratedValue(generator = "uuid2")
#GenericGenerator(name = "uuid2", strategy = "uuid2")
#Column(columnDefinition = "BINARY(16)")
private UUID userId;
#NotEmpty
private String username;
#NotEmpty
private String password;
#NotEmpty
private String email;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "user", cascade = CascadeType.ALL)
#OnDelete(action = OnDeleteAction.CASCADE)
#JsonIgnore
private Set<TahographCard> tahographCards;
private String comments;
protected User(){}
public User(String username, String password, String email){
setUsername(username);
setPassword(password);
setEmail(email);
setComments(EMPTY_STRING);
setTahographCards();
}
//getters and setters
}
TahographCard:
package com.getmydrivercard.getmydrivercard.models;
import org.hibernate.annotations.GenericGenerator;
import javax.persistence.*;
import javax.validation.constraints.NotEmpty;
import java.util.UUID;
#Entity
#Table(name = "tahograph_cards")
public class TahographCard {
#Id
#GeneratedValue(generator = "uuid2")
#GenericGenerator(name = "uuid2", strategy = "uuid2")
#Column(columnDefinition = "BINARY(16)")
private UUID tahographCardId;
#NotEmpty
private Boolean isActive;
#NotEmpty
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "userId")
private User user;
protected TahographCard(){}
public TahographCard(User user){
setUser(user);
setActive(true);
}
//getters and setters
}
I tried with mappedBy and some other stuff I found on the Internet but still doesn't work. Thank you in advance.
The problem here is not the entities configuration but the database design.
You can't map a oneToMany relationship with a FK column on the one side.
For example if you have 2 Users and 4 TahographCard (2 for each user) normally it would look like this:
User
id name
1 Foo
2 Bar
Table
id user_id (fk)
1 1
2 1
2 2
2 2
The opposite with the TahographCardId on the User table is impossible