当我使用@IdClass时,LinkedHashSet包含重复的项目

时间:2012-03-10 22:26:43

标签: java hibernate jpa linkedhashset

我的任务是准备报价搜索屏幕。我已经提到了Oracle视图 创建报价模型。由于视图表中没有id列,我更喜欢通过quoteId.class使用@IdClass注释来使用复合id。我在两个模型上覆盖hashCode和equals方法。 quoteId等于& hashcode返回所有字段的组合并引用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甚至包含所有项目的报价编号相同。我是否缺少任何其他实现来证明每个项目的唯一性通过引用no字段(比较,比较)?如果我跟踪uniqueQuoteResult列表项值,则所有值都具有相同的引号。

编辑注意:我已经改变了使用apache库HashCodeBuilder和EqualsBuilder支持的方法,但问题保持不变。我担心idClass哈希码对于linkedhashset

有效

1 个答案:

答案 0 :(得分: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&#39; s的相等性,而不是像:

this.quoteNo.equals(other.quoteNo);

当前在模型中实现equals时还存在一些其他问题(例如,它可能抛出ClassCastException)。基本原则可以从以下网址找到:Object.equalsOverriding the java equals() method quirk。 另外,对于Hibernate,重要的是要记住,您不应该测试类是否相同,而是使用instanceof(因为代理类)。关于为实体编写equals&amp; hascode的一些说明可以从Hibernate documentation找到。

修改 您当前的方法不起作用,因为

 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));