我希望按年龄排序;
在这种情况下 compareTo()的方法运行正常,但问题是 remove()和 contians()方法总是返回 假
有趣:如果我从compareTo()方法取消注释行,remove()和contains()方法工作正常;但是我想用另一个字段作为排序。
有人知道为什么不能正常工作;发现旧的Hibernate问题:https://hibernate.atlassian.net/browse/HHH-2634; 这已经修好了吗?
Bellow是使用过的课程:
@Entity(name = "CAMPAIGN")
public class Campaign implements Identifiable, Serializable {
public static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "ID")
private Long id;
@OneToMany(mappedBy = "campaign", cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true)
@OrderBy("age ASC")
private SortedSet<MailingAddress> mailingAddresses = new TreeSet<>();
...
public void removeMailingAddress(MailingAddress mailingAddress) {
this.mailingAddresses.remove(mailingAddress);
//this.mailingAddresses.contains(mailingAddress);
mailingAddress.setCampaign(null);
}
}
和
@Entity(name = "MAILING_ADDRESS")
public class MailingAddress implements Identifiable, Comparable, Serializable {
public static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "ID")
private Long id;
@ManyToOne
@JoinColumn(name = "CAMPAIGN_ID")
private Campaign campaign;
@Column(name = "AGE")
private Integer age;
@Override
public int compareTo(Object o) {
if (o == null) {
return 1;
}
if (!(o instanceof MailingAddress)) {
throw new ClassCastException("Cannot compare MailingAddress with " + o.getClass());
}
MailingAddress o1 = (MailingAddress) o;
int comparison;
// comparison for id
/*comparison = compareFields(this.id, o1.id);
if (comparison != 0) {
return comparison;
}*/
// comparison for ageBand
comparison = compareFields(this.age, o1.age);
if (comparison != 0) {
return comparison;
}
return 0;
}
private int compareFields(Comparable field1, Comparable field2) {
if (field1 == null && field2 == null) {
return 0;
} else if (field1 == null && field2 != null) {
return -1;
} else if (field1 != null && field2 == null) {
return 1;
}
return field1.compareTo(field2);
}
@Override
public boolean equals(Object o) {
return this.compareTo(o) == 0;
}
}
更新
发现使用 SortedSet 作为 TreeSet 的界面并结合 Hibernate ,方法remove()和contains()无法正常工作。 &#34; SortedSet mailingAddresses = new TreeSet&lt;&gt;();&#34;
将定义更改为&#34;设置mailingAddresses = new TreeSet&lt;&gt;();&#34; 以及方法 remove()和 contains()工作正常;此外,使用compareTo()的排序也适用于除 id 之外的其他字段。
TreeSet,SortedSet和Hibernate 的组合可能存在一个错误。如果有人找到了这个问题的解释&#34; bug&#34;请告诉我。
这是一个工作版本:
@Entity
public class MailingAddress implements Identifiable, Comparable, Serializable {
public static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "ID")
private Long id;
private Integer age;
@Override
public int compareTo(Object o) {
if (o == null) {
return 1;
}
if (!(o instanceof MailingAddress)) {
throw new ClassCastException("Cannot compare MailingAddress with " + o.getClass());
}
MailingAddress o1 = (MailingAddress) o;
int comparison = compareFields(this.age, o1.age);
if (comparison != 0) {
return comparison;
}
return 0;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MailingAddress that = (MailingAddress) o;
if (id != null ? !id.equals(that.id) : that.id != null) return false;
return age != null ? age.equals(that.age) : that.age == null;
}
@Override
public int hashCode() {
return 31;
}
private int compareFields(Comparable field1, Comparable field2) {
if (field1 == null && field2 == null) {
return 0;
} else if (field1 == null && field2 != null) {
return -1;
} else if (field1 != null && field2 == null) {
return 1;
}
return field1.compareTo(field2);
}
}
和
@Entity
public class Campaign implements Identifiable, Serializable {
public static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "ID")
private Long id;
@OneToMany(mappedBy = "campaign", cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true)
@OrderBy("age ASC")
private Set<MailingAddress> mailingAddresses = new TreeSet<>();
...
}
答案 0 :(得分:2)
这里的问题是你重写equals而不重写hashCode。正如this article中所述,您需要提供两者。此外,引用检查不适用于合并entity state transition。
由于MailingAddress
中没有自然的业务键,因此您需要使用如下的实体标识符:
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof MailingAddress)) return false;
MailingAddress ma = (MailingAddress) o;
return getId() != null && Objects.equals(getId(), ma.getId());
}
@Override
public int hashCode() {
return 31;
}
检查this article以了解为什么hashCode在这种情况下需要返回一个常量值。
但是,并非全部。
为什么使用TreeSet
和@OrderBy("age ASC")
。订单在查询时给出,然后在Java中覆盖它。由于您使用@OrderBy
,因此在执行SELECT语句时完成排序后使用List
会更有意义。