我有两个通过映射表将N关联到N的实体,而该实体本身是如下实体
Rule 1<-->N Mapping N<-->1 Preference
它们两者都通过HashSet <>
实现关系Rule.java
/**
* List of {@link RulePreferenceMapping} belonging to this {@link Rule}
*/
@OneToMany(
mappedBy = "rule",
cascade = CascadeType.ALL,
fetch = FetchType.EAGER
)
private Set<RulePreferenceMapping> preferenceMappingList = new HashSet<>();
@Override
public boolean equals(Object o)
{
if (this == o)
{
return true;
}
if (o == null || getClass() != o.getClass())
{
return false;
}
return new EqualsBuilder()
.appendSuper(super.equals(o))
.isEquals();
}
@Override
public int hashCode()
{
return new HashCodeBuilder(17, 37)
.appendSuper(super.hashCode())
.toHashCode();
}
RulePreference.java
/**
* List of {@link RulePreferenceMapping} pointing to this element
*/
@OneToMany(
mappedBy = "rulePreference",
cascade = CascadeType.ALL,
fetch = FetchType.EAGER
)
private Set<RulePreferenceMapping> ruleMappingList = new HashSet<>();
@Override
public boolean equals(Object o)
{
if (this == o)
{
return true;
}
if (o == null || getClass() != o.getClass())
{
return false;
}
RulePreference that = (RulePreference) o;
return new EqualsBuilder()
.append(name, that.name)
.isEquals();
}
@Override
public int hashCode()
{
return new HashCodeBuilder(17, 37)
.append(name)
.toHashCode();
}
RulePreferenceMapping.java
/**
* {@link Rule} this element belongs to
*/
@ManyToOne(optional = false, fetch = FetchType.EAGER)
@JoinColumn(name = "rule_id")
private Rule rule;
/**
* {@link RulePreference} this mapping points to
*/
@ManyToOne(optional = false, fetch = FetchType.EAGER)
@JoinColumn(name = "rule_preference_id")
private RulePreference rulePreference;
@Override
public boolean equals(Object o)
{
if (this == o)
{
return true;
}
if (o == null || getClass() != o.getClass())
{
return false;
}
RulePreferenceMapping that = (RulePreferenceMapping) o;
return new EqualsBuilder()
.append(rule, that.rule)
.append(rulePreference, that.rulePreference)
.isEquals();
}
@Override
public int hashCode()
{
return new HashCodeBuilder(17, 37)
.append(rule)
.append(rulePreference)
.toHashCode();
}
Rule.java扩展了 @MappedSuperclass 的AbstractEntity,并且仅包含一个属性
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
protected Integer id;
@Override
public boolean equals(Object o)
{
if (this == o)
{
return true;
}
if (o == null || getClass() != o.getClass())
{
return false;
}
AbstractEntity that = (AbstractEntity) o;
return new EqualsBuilder()
.append(id, that.id)
.isEquals();
}
@Override
public int hashCode()
{
return new HashCodeBuilder(17, 37)
.append(id)
.toHashCode();
}
Rule与 RuleLevel.java 有另一个关系(没有映射表,只是一个正常的1到N关系)
/**
* {@link RuleLevel} this {@link Rule} belongs to
*/
@ManyToOne(optional = false, fetch = FetchType.EAGER)
@JoinColumn(name = "rule_level_id")
private RuleLevel ruleLevel;
我有一个用于测试的嵌入式HSQLDB
CREATE TABLE IF NOT EXISTS rule_level (
id INTEGER GENERATED BY DEFAULT AS IDENTITY NOT NULL,
name VARCHAR(255) NOT NULL,
updated TIMESTAMP NOT NULL,
PRIMARY KEY (id),
);
INSERT INTO rule_level (id, name, updated)
VALUES
(1, 'Country wide', current_timestamp),
(2, 'Department wide', current_timestamp),
(3, 'City wide', current_timestamp);
CREATE TABLE IF NOT EXISTS rule (
id INTEGER GENERATED BY DEFAULT AS IDENTITY NOT NULL,
name VARCHAR(255) NOT NULL,
information VARCHAR(512) NULL,
rule_level_id INT NULL,
updated TIMESTAMP NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (rule_level_id) REFERENCES rule_level(id),
);
INSERT INTO rule (id, name, information, rule_level_id, updated)
VALUES
(1, 'Rule 1', 'Information Rule 1', 1, current_timestamp),
(2, 'Rule 2', null, 1, current_timestamp),
(3, 'Rule 3', null, null, current_timestamp),
(4, 'Rule 4', 'Information Rule 4', null, current_timestamp);
CREATE TABLE IF NOT EXISTS rule_preference (
id INTEGER GENERATED BY DEFAULT AS IDENTITY NOT NULL,
name VARCHAR(255) NOT NULL,
updated TIMESTAMP NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE IF NOT EXISTS rule_preference_mapping (
id INTEGER GENERATED BY DEFAULT AS IDENTITY NOT NULL,
rule_id INT NOT NULL,
rule_preference_id INT NOT NULL,
updated TIMESTAMP NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (rule_id) REFERENCES rule(id),
FOREIGN KEY (rule_preference_id) REFERENCES rule_preference(id),
INSERT INTO rule_preference (id, name, updated)
VALUES
(1, 'Preference 1', current_timestamp),
(2, 'Preference 2', current_timestamp),
(3, 'Preference 3', current_timestamp);
INSERT INTO rule_preference_mapping (id, rule_id, rule_preference_id, updated)
VALUES
(1, 1, 1, current_timestamp), -- set rule #1 to preference #1
(2, 2, 1, current_timestamp), -- set rule #2 to preference #1
(3, 3, 1, current_timestamp), -- set rule #3 to preference #1
(4, 1, 2, current_timestamp), -- set rule #1 to preference #2
(5, 2, 2, current_timestamp), -- set rule #2 to preference #2 **-- DON'T LOAD**
(6, 3, 2, current_timestamp); -- set rule #3 to preference #2 **-- DON'T LOAD**
我的怪异问题是,只要我的Rule的RuleLevel值为 NULL ,就只能从DB加载到首选项的一个映射。 对于此数据集,我的Rule#1将包含3个首选项映射(标识1、2和3),但是我的Rule#2将仅包含映射4。其他两个根本不会添加到集合中。我当然认为我的equals()和hashCode()发生了什么,但实际上没有。
只要我为规则设置一个级别,它就会按预期加载。
环境:Java8,带有Hibernate的Spring JPA