JDK 17 SpringBoot latest JPA latest MySQL 8.0.31
I am trying to implement a strategy that makes sure that both the name and the email address of each user are unique.
User entity:
@Entity
public class User {
......
@EmbeddedId
protected UserId id;
......
}
User id:
@Embeddable
public class UserId implements Serializable {
@Serial
private static final long serialVersionUID = -622156255674132106L;
@Column(name = "name", nullable = false)
protected String name = "";
@Column(name = "email", nullable = false)
protected String email = "";
public UserId(String name, String email) {
setName(name);
setEmail(email);
}
public UserId() {}
public void setName(String name) {
this.name = name;
}
public String getName() {
return Objects.requireNonNullElse(name, "");
}
public void setEmail(String email) {
this.email = email;
}
public String getEmail() {
return Objects.requireNonNullElse(email, "");
}
}
Now, by default, it is marked as a conflict only if userA.name == userB.name && userA.email == userB.email
, which means there can be two users having the same email address as long as they do not share one single name. How to stop this from happening? What I expect is userA.name == userB.name || userA.email == userB.email
.
I've tried overriding equals()
and hashcode()
in the following way.
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof UserId userId)) return false;
if (Objects.equals(name, userId.name)) return true;
return Objects.equals(email, userId.email);
}
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result (email != null ? email.hashCode() : 0);
return result;
}
However, it does not work. Also, breakpoints inside these two functions are not reached.
CodePudding user response:
Whether you do this via annotations and schema generation, or just by creating / modifying the schema directly, the answer is the same.
You will need to create a single unique constraint in the database naming both columns, not two separate constraints.
If you want a schema generation annotation to do this, supply the @UniqueConstraint annotation to the @Table annotation, e.g.
@Table(uniqueConstraints = {
@UniqueConstraint(columnNames = {
"name", "email"
})
})
CodePudding user response:
You add the unique constraint to username and email. https://www.baeldung.com/jpa-unique-constraints
public class UserId implements Serializable {
@Serial
private static final long serialVersionUID = -622156255674132106L;
@Column(name = "name", nullable = false, unique=true)
protected String name = "";
@Column(name = "email", nullable = false, unique=true)
protected String email = "";