当前位置: 代码迷 >> java >> 如何修复正确添加到 Set Hibernate Entity
  详细解决方案

如何修复正确添加到 Set Hibernate Entity

热度:21   发布时间:2023-07-25 19:48:35.0

我读了一篇关于正确重定义 equals/hashCode 的文章: :

执行这些覆盖是为了不丢失已写入 Set 的记录。

代码:

@Entity
public class Client {

    @Id
    @Column
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column
    private String name;

    public Client() {
    }

    public Client(String name) {
        this.name = name;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Client client = (Client) o;
        return Objects.equals(id, client.id) &&
                Objects.equals(name, client.name);
    }

    public int hashCode() {
        return 31;
    }

    @Override
    public String toString() {
        final StringBuilder sb = new StringBuilder("Client{");
        sb.append("id=").append(id);
        sb.append(", name='").append(name).append('\'');
        sb.append('}');
        return sb.toString();
    }
}

然后我测试我的课程以确保它正常工作:

@Transactional
public class ClientTest {

    @PersistenceContext
    protected EntityManager em;

    @Test
    public void storeToSetBeforeMerge_ShouldBeContains() {
        Set<Client> map = new HashSet<>();
        Client client1 = new Client("John");
        Client client2 = new Client("Mike");
        map.add(client1);
        map.add(client2);

        Client merge1 = em.merge(client1);
        Client merge2 = em.merge(client2);

        assertTrue(map.contains(merge1));   // not true!
        assertTrue(map.contains(merge2));   // not true!
    }
}

我的问题是为什么不满足条件。 毕竟,我已经指出 hashCode 返回相同的值:31。我做错了什么?

我无法理解这个决定的意义。 如果这个解决方案没有解决问题,我无法从 Set 中找到我需要的元素

这是因为HashSet不仅仅是比较hashCode结果。 它的作用如下:

  1. 它比较hashCode的结果,如果结果不同,则返回 true。
  2. 如果hashCode结果相同,则使用equals比较对象并返回结果。

这是因为性能 - 计算hashCode更快,建议hashCode不要经常产生冲突。

编辑

在您的equals方法中,您使用id进行比较,这是错误的,因为 id 是由数据库生成的:

public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    Client client = (Client) o;
    return Objects.equals(id, client.id) && // <- comparison by id
            Objects.equals(name, client.name);
}

在您的测试中,您正在创建没有 id 的对象并将它们放入HashSet ,然后您正在生成 id 并再次检查Collection

@Test
public void storeToSetBeforeMerge_ShouldBeContains() {
    Set<Client> map = new HashSet<>();
    Client client1 = new Client("John");
    Client client2 = new Client("Mike");
    map.add(client1); // <- those don't have an id
    map.add(client2);

    Client merge1 = em.merge(client1); // those do have an id
    Client merge2 = em.merge(client2);

    assertTrue(map.contains(merge1));   // whose with id are not in set
    assertTrue(map.contains(merge2));
}

您没有像文章中那样在merge() persist()之前调用persist() 文章作者在第一条评论中对此进行了解释。

合并用于集成先前已持久化的分离实体上的更改。

新实体的生命周期从persist()开始。 然后在具有 ID 的分离实体上调用merge() ,条件将被满足。

  相关解决方案