简体   繁体   中英

Overriding equals() and hashcode() methods in JPA embeddable does not work

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 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.

==========Edited==========

I've solved the original problem. But when it comes to UsersRepository.existsById() , it's still considered not to exist if either of the two columns does not match. How can I fix it?

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, eg

@Table(uniqueConstraints = { 
 @UniqueConstraint(columnNames = {
   "name", "email" 
 }) 
})
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 = "";

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