在 equals 方法中仅包含实体 id 时,无法将新实体添加到集合中

问题描述 投票:0回答:1

我想问一下实体上有 equals 方法。 我正在运行一个设置,其中我仅根据 Id 比较实体,并认为这是最好的做事方式。然而我意识到,当使用级联持久保存新的 UserRoles 时,我遇到了问题,它们最初并不唯一,因为它们还没有 id。所以我无法将它们添加到集合中。

所以我的问题是,仅使用 id 字段是否是一个好方法?使用级联来持久化相关实体是一个好方法吗?就我而言,似乎我必须将用户和角色字段添加到 Equals(我不想这样做,因为我不想一直急切地加载它们),或者只是单独保留 userRoles。

背景:

@Entity
@Getter
@Setter
@ToString(exclude = {"user", "role"})
@EqualsAndHashCode(onlyExplicitlyIncluded = true, callSuper = false)
@NoArgsConstructor
@AllArgsConstructor
@Table(name="kasutaja_roll")
public class UserRole extends BaseEntity {

    @Id
    @SequenceGenerator(name = "kasutaja_roll_id_seq", sequenceName = "kasutaja_roll_id_seq", allocationSize = 1)
    @GeneratedValue(generator = "kasutaja_roll_id_seq", strategy = GenerationType.SEQUENCE)
    @EqualsAndHashCode.Include
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "kasutaja_id")
    private User user;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "roll_id")
    private Role role;

    @Column(name = "kehtiv_alates")
    private Instant validFrom;

    @Column(name = "kehtiv_kuni")
    private Instant validUntil;

    public UserRole(User user, Role role) {
        super();
        this.validFrom = Instant.now();
        this.user = user;
        this.role = role;
    }

}

@Entity
@Getter
@Setter
@ToString(exclude = {"roles"})
@EqualsAndHashCode(onlyExplicitlyIncluded = true, callSuper = false)
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "kasutaja")
public class User extends BaseEntity{

    @Id
    @SequenceGenerator(name = "kasutaja_id_seq", sequenceName = "kasutaja_id_seq", allocationSize = 1)
    @GeneratedValue(generator = "kasutaja_id_seq", strategy = GenerationType.SEQUENCE)
    @EqualsAndHashCode.Include
    private Long id;

    @OneToMany(mappedBy = "user", cascade={CascadeType.PERSIST, CascadeType.MERGE})
    private Set<UserRole> roles;

...

例如像这样添加它们:

for (Long roleId : requestDto.getRoles()) {
            UserRole existingUserRole = existingUserRolesByRoleId.get(roleId);

            if (existingUserRole == null) {
                // No existing userRoll - create new one
                Role role = roleRepository.findById(roleId)
                        .orElseThrow(() -> new IllegalArgumentException("Role not found with id: " + roleId));
                UserRole newUserRole = new UserRole(user, role);
                user.getRoles().add(newUserRole); //!!!here adding multiple ones fails because they are equal, since id = null!!!
            } else if (existingUserRole.getValidUntil() != null) {
                // Existing userRole is inactive - reactivate it
                existingUserRole.setValidUntil(null);
                existingUserRole.setValidFrom(now);
            }
            //existing userRole is active, do nothing
        }

hibernate jpa entity persistence equals
1个回答
0
投票

所以我的问题是,仅使用 id 字段是否是一个好方法?

简短的答案是否定的,不是,较长的答案是这取决于情况,并且您需要考虑新实例。

有很多文章(例如 this)解释了如何为 JPA 编写正确的

equals
/
hashCode
方法。您需要考虑一些特殊性。

其次,JPA 和 Lombok 通常不是朋友,这是我的经验(请参阅我的这篇文章),应该避免。但这可能是个人恩怨。

话虽如此,您可能应该自己写

equals
/
hashCode
。基本的 JPA 实现(带有新的 Java 构造)可能是这样的。

@Override
public boolean equals(Object that) {
  if (that instanceof UserRole ur) {
    return this.id != null && Objects.equals(this.id, that.id)
  }
  return false;
}

@Override
public int hashCode() {
  return getClass().hashCode();
}

这样的东西应该有效。

instanceof
检查可以变得更加智能,您甚至可以在
BaseEntity
中提供类似的内容。

© www.soinside.com 2019 - 2024. All rights reserved.