使用 Hibernate 和 TreeSet 对 remove() 和 contains() 方法不起作用
Using Hibernate and TreeSet does not work the remove() and contains() methods
我想要一个按年龄排序的集合;
在这种情况下,方法 compareTo() 工作正常,但问题是 remove() 和 contians () 方法 returns 总是 false;
有趣: 如果我取消对 compareTo() 方法行的注释,remove() 和 contains() 方法可以正常工作;但我想使用其他字段作为排序。
有人知道为什么不能正常工作吗?发现旧的 Hibernate 问题:https://hibernate.atlassian.net/browse/HHH-2634;
这已经修复了吗?
下面是使用过的 类:
@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 方法删除() 和 contains() 无法正常工作。
"SortedSet mailingAddresses = new TreeSet<>();"
将定义更改为 "Set mailingAddresses = new TreeSet<>();" 以及方法 remove() 和 contains() 工作正常;此外,使用 compareTo() 的排序也适用于 id.
以外的其他字段
TreeSet、SortedSet 和 Hibernate 的组合可能存在错误。如果有人对此 "bug" 找到了解释,请告诉我。
这是一个工作版本:
@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<>();
...
}
这里的问题是你覆盖了 equals
而没有覆盖 hashCode
.
此外,引用检查不适用于合并实体状态转换。
由于您在 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 getClass().hashCode();
}
getClass().hashCode()
returns 是所有实例的常量值,因此允许在 HashSet
中找到具有 null
id
的实体,甚至在瞬态实体上调用 persist
后更改 id
之后。
但是,这还不是全部。
为什么要用 TreeSet
和 @OrderBy("age ASC")
。该顺序在查询时给出,然后您在 Java 中覆盖它。由于您使用 @OrderBy
,因此使用 List
更有意义,因为排序是在执行 SELECT 语句时完成的。
我想要一个按年龄排序的集合;
在这种情况下,方法 compareTo() 工作正常,但问题是 remove() 和 contians () 方法 returns 总是 false;
有趣: 如果我取消对 compareTo() 方法行的注释,remove() 和 contains() 方法可以正常工作;但我想使用其他字段作为排序。
有人知道为什么不能正常工作吗?发现旧的 Hibernate 问题:https://hibernate.atlassian.net/browse/HHH-2634; 这已经修复了吗?
下面是使用过的 类:
@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 方法删除() 和 contains() 无法正常工作。 "SortedSet mailingAddresses = new TreeSet<>();"
将定义更改为 "Set mailingAddresses = new TreeSet<>();" 以及方法 remove() 和 contains() 工作正常;此外,使用 compareTo() 的排序也适用于 id.
以外的其他字段TreeSet、SortedSet 和 Hibernate 的组合可能存在错误。如果有人对此 "bug" 找到了解释,请告诉我。
这是一个工作版本:
@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<>();
...
}
这里的问题是你覆盖了 equals
而没有覆盖 hashCode
.
此外,引用检查不适用于合并实体状态转换。
由于您在 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 getClass().hashCode();
}
getClass().hashCode()
returns 是所有实例的常量值,因此允许在 HashSet
中找到具有 null
id
的实体,甚至在瞬态实体上调用 persist
后更改 id
之后。
但是,这还不是全部。
为什么要用 TreeSet
和 @OrderBy("age ASC")
。该顺序在查询时给出,然后您在 Java 中覆盖它。由于您使用 @OrderBy
,因此使用 List
更有意义,因为排序是在执行 SELECT 语句时完成的。