Criteria.DISTINCT_ROOT_ENTITY 不防止重复的对象

Criteria.DISTINCT_ROOT_ENTITY doesn't prevent duplicated objects

我有以下dao方法:

@Override
public List<AdminRole> findAll() {
    Session session = sessionFactory.getCurrentSession();
    Criteria criteria = session.createCriteria(AdminRole.class);
    criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
    return criteria.list();
}

实际上我想从数据库中检索所有条目。

有时我会看到重复的内容。当我使用 AdminRole 添加用户时会发生这种情况。

我读到当我使用 EAGER 获取类型时是可能的,这应该是修复添加以下行:

criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);

但这对我没有帮助。

我的映射:

@Entity
@Table(name = "terminal_admin_role")
public class AdminRole {

    @Id
    @Column(name = "role_id", nullable = false, unique = true)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "user_id")
    @SequenceGenerator(name = "user_id", sequenceName = "user_id")
    private Long adminId;

    @Column(name = "role")
    private String role;

    public AdminRole(String role) {
        this.role = role;
    }

    public AdminRole() {
    }

    // get set

    @Override
    public String toString(){
        return role;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (!(o instanceof AdminRole)) {
            return false;
        }

        AdminRole adminRole = (AdminRole) o;

        if (!role.equals(adminRole.role)) {
            return false;
        }

        return true;
    }

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

@Entity
@Table(name = "terminal_admin")
public class TerminalAdmin {
    @ManyToMany(fetch=FetchType.EAGER,cascade=CascadeType.ALL)
    @JoinTable(name = "admin_role", joinColumns = { 
        @JoinColumn(name = "admin_id", nullable = false) }, 
        inverseJoinColumns = { @JoinColumn(name = "role_id", 
                nullable = false) })
    private Set<AdminRole> adminRoles;      
    //...
}

P.S.

我无法切换获取类型。

我不想将此列表放入集合中。

没有理由使用 DISTINCT_ROOT_ENTITY 或类似的东西,您只需要:

session.createCriteria(AdminRole.class).list();

如果你得到重复项,那么你确实在数据库中有它们。检查直接或通过从其他实体级联保存 AdminRoles 的代码。

当从其他实体级联 PERSIST/MERGE 操作时,确保操作级联到 persistent/detached AdminRole 实例,而不是瞬态(新) 一个。

我的钱花在搞乱 hashCode/equals 覆盖和 Hibernate 代理上。

来自EqualsandHashCode

However, once you close the Hibernate session, all bets are off. [...] Hence, if you keep collections of objects around between sessions, you will start to experience odd behavior (duplicate objects in collections, mainly).

首先,我会像这样使用 org.apache.commons.lang3(这对于 Hibernate 实体来说显然太昂贵了,但与它们一起工作正常,如果它工作应该验证我的直觉):

import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;


@Override
public String toString() {
    return ToStringBuilder.reflectionToString(this);
}

@Override
public int hashCode() {
    return HashCodeBuilder.reflectionHashCode(this);
}

@Override
public boolean equals(Object other) {
    return EqualsBuilder.reflectionEquals(this, other);
}

如果这行得通,您可以采用像这样的更便宜的方法:

@Override
public int hashCode() {
    HashCodeBuilder hcb = new HashCodeBuilder();
    hcb.append(role);
    return hcb.toHashCode();
}

@Override
public boolean equals(Object obj) {
    if (this == obj) {
        return true;
    }
    if (!(obj instanceof AdminRole)) {
        return false;
    }
    AdminRole that = (AdminRole) obj;
    EqualsBuilder eb = new EqualsBuilder();
    eb.append(role, that.role);
    return eb.isEquals();
}