1

我的任务是准备一个报价搜索屏幕。我参考了一个 Oracle 视图来创建报价模型。由于视图表中没有 id 列,我更喜欢通过 quoteId.class 使用 @IdClass 注释使用复合 id。我在两个模型上都覆盖了 hashCode 和 equals 方法。quoteId equals & hashcode 返回所有字段的组合,quote hashcode & equals 只是比较模型中的 this.quoteNo 字段。

报价型号:

@Override
public int hashCode()
{
    return new HashCodeBuilder(17,37)
    .append(quoteNo)
    .toHashCode();
}

/*
 * (non-Javadoc)
 * 
 * @see java.lang.Object#equals(java.lang.Object)
 */
@Override
public boolean equals(Object obj)
{
    final quoteModel other = (quoteModel ) obj;
    return new EqualsBuilder().appendSuper(super.equals(other))
            .append(quoteNo, other.quoteNo).isEquals();
}

当我需要独特的物品时,我只是通过以下方式访问:

uniqueQuoteResults = new ArrayList<Quote>(
                    new LinkedHashSet<Quote>(fullQuoteResults));

但是当我开始使用 idClass 时,我的linkedHashSet 包含所有项目,甚至它们的报价编号都相同。我是否缺少任何其他实现来通过引用无字段(可比较,比较器)来证明每个项目的唯一性?如果我跟踪 uniqueQuoteResult 列表项的值,它们都具有相同的报价编号。

编辑注意:我已经改变了使用 apache 库 HashCodeBuilder 和 EqualsBuilder 支持的方式,但问题仍然存在。我担心 idClass 哈希码对linkedhashset 生效

4

1 回答 1

2

在您的模型中使用以下代码,您测试的是 this.quoteNo 与 obj.quoteNo 相同的实例:

@Override
public boolean equals(Object obj)
{
    // TODO Auto-generated method stub
    return this.quoteNo == ((EprocAwquoteV) obj).quoteNo;
}

结果是,如果 quoteNo 不是同一个对象,则具有单独构造的 IdClass 实例的两个实例将被认为不相等。我猜你想用类似的东西来测试quoteNo的相等性:

this.quoteNo.equals(other.quoteNo);

模型中equals的当前实现还有一些其他问题(例如它可以抛出ClassCastException)。基本原理可以参考:Object.equalsOverriding the java equals() method quirk。此外,对于 Hibernate,重要的是要记住,您不应该测试类相同,而是使用 instanceof 代替(因为代理类)。可以从Hibernate 文档中找到有关为实体编写 equals&hascode 的一些说明。

编辑: 您当前的方法不起作用,因为

 return new EqualsBuilder().appendSuper(super.equals(other))

归结为 Object.equals。如果您没有具有有意义的 equals 实现的超类。我不完全确定我是否理解你的情况,所以也许你可以看看下面的工作示例,找出不同之处:

public class QuoteId implements Serializable {
    private int id1;
    private int id2;

    public QuoteId() {}

    //This equals does not matter when we build LinkedHashSet
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        QuoteId other = (QuoteId) o;
        return id1 == other.id1 && id2 == other.id2;
    }

    public int hashCode() {
        return 31 * id1 + id2;
    }
}

@Entity
@IdClass(QuoteId.class)
public class Quote {
    @Id private int id1;
    @Id private int id2;
    String value;

    public Quote() {
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Quote other = (Quote) o;
        return id1 == other.id1 && id2 == other.id2;
    }

    @Override
    public int hashCode() { return 31 * id1 + id2;}

    //get&set for id1, id2, and value are omitted
}


tx.begin();
em.persist(new Quote(1, 1, "val"));
em.persist(new Quote(1, 2, "val"));
tx.commit();

TypedQuery<Quote> query = em.createQuery("SELECT q FROM Quote q", Quote.class);
List<Quote> twoQuotes = query.getResultList();//both

//duplicating (size=4) result for sake of test;
List<Quote> fullQuoteResults = new ArrayList<Quote>();
fullQuoteResults.addAll(twoQuotes);
fullQuoteResults.addAll(twoQuotes);

//will have same elements as in twoQuotes:
List<Quote> uniqueQuoteResults = new ArrayList<Quote>(
        new LinkedHashSet<Quote>(fullQuoteResults));
于 2012-03-11T18:37:57.003 回答