在创建JPA实体方面,应该和不应该进入equals和hashcode。作为一个例子,我有一个地址实体如下。
我已经读过不应该包含ID,但不确定原因。在我的例子中,像State这样的嵌套对象怎么样?我没有包含位置,因为State是非拥有者,Location拥有这种关系。
以下类在equals和hashcode中应该和不应该是什么?
@Entity
@Table(name = "T_ADDRESS")
@XmlRootElement
@EqualsAndHashCode(exclude = {"id", "locations"})
@ToString(exclude = {"location"})
public class Address implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "addressSeq")
@SequenceGenerator(name = "addressSeq", sequenceName = "T_ADDRESS_SEQ", allocationSize = 1)
@Column(name = "ID")
private Long id;
@Size(max = 255)
@Column(name = "STREET_LINE_1")
private String streetLine1;
@Size(max = 255)
@Column(name = "STREET_LINE_2")
private String streetLine2;
@NotBlank
@Size(max = 255)
@Column(name = "CITY")
private String city;
@ManyToOne(fetch = FetchType.EAGER, optional = false)
@JoinColumn(name = "STATE_ID", referencedColumnName = "ID")
private State state;
@NotBlank
@Size(max = 10)
@Column(name = "POSTAL_CODE")
private String postalCode;
// Referenced Properties
@OneToMany(fetch = FetchType.LAZY, mappedBy = "address")
private List<Location> locations;
public Address() {
}
public Address(String streetLine1, String streetLine2, String city, State state, String postalCode) {
this.streetLine1 = streetLine1;
this.streetLine2 = streetLine2;
this.city = city;
this.state = state;
this.postalCode = postalCode;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getStreetLine1() {
return streetLine1;
}
public void setStreetLine1(String streetLine1) {
this.streetLine1 = streetLine1;
}
public String getStreetLine2() {
return streetLine2;
}
public void setStreetLine2(String streetLine2) {
this.streetLine2 = streetLine2;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public State getState() {
return state;
}
public void setState(State state) {
this.state = state;
}
public String getPostalCode() {
return postalCode;
}
public void setPostalCode(String postalCode) {
this.postalCode = postalCode;
}
public List<Location> getLocations() {
return locations;
}
public void setLocations(List<Location> locations) {
this.locations = locations;
}
}
答案 0 :(得分:1)
我最常见的建议是,实体的相等性应该反映出业务逻辑的适当的平等意识,而不是持久性逻辑。如果您使用代理ID而不是自然ID,就像使用JPA一样,那么这意味着您在其ID上 not 基本实体的相等性。
考虑:假设您从数据库加载Address
实体,并且还基于通过应用程序UI提供的数据构建一个实体。如果您希望它们有可能彼此测试为equals()
,那么您必须仅将该测试基于而不是 ID,因为后者对象还没有任何已分配ID。这取决于您应该为该测试做出哪些属性。
当然,如果您覆盖equals()
,那么您也应该覆盖hashCode()
以确保任何两个测试equals()
的对象具有相同哈希码的不变量。为此,您可以仅使用有助于哈希代码计算中的相等性测试的属性,并且对于最有区别的哈希代码,您应该使用所有这些属性。
请注意,如果实体与一个或多个其他实体有关联,则其他实体的ID可能会合理地考虑到相等性测试。例如,您的Address
实体可能会在State
和equals()
次确认中包含其关联的hashCode()
实体的ID。
答案 1 :(得分:0)
这取决于您的业务&#34;规则。在以下情况下,两个Address实例是等效的:
(例如,也许您还需要包含streetline2)
您还可以通过创建新属性state_id来更改编写equals()和hashcode()方法的方法。它将包含状态标识符而不提取&#34;状态&#34;实体:
@Column(name="STATE_ID", insertable=false, updatable=false)
private Long stateId;
@ManyToOne(fetch = FetchType.EAGER, optional = false)
@JoinColumn(name = "STATE_ID", referencedColumnName = "ID")
private State state;