应该包含在JPA实体的equals和hashcode中

时间:2015-09-29 20:39:40

标签: java hibernate jpa

在创建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;
    }
}

2 个答案:

答案 0 :(得分:1)

我最常见的建议是,实体的相等性应该反映出业务逻辑的适当的平等意识,而不是持久性逻辑。如果您使用代理ID而不是自然ID,就像使用JPA一样,那么这意味着您在其ID上 not 基本实体的相等性。

考虑:假设您从数据库加载Address实体,并且还基于通过应用程序UI提供的数据构建一个实体。如果您希望它们有可能彼此测试为equals(),那么您必须仅将该测试基于而不是 ID,因为后者对象还没有任何已分配ID。这取决于您应该为该测试做出哪些属性。

当然,如果您覆盖equals(),那么您也应该覆盖hashCode()以确保任何两个测试equals()的对象具有相同哈希码的不变量。为此,您可以仅使用有助于哈希代码计算中的相等性测试的属性,并且对于最有区别的哈希代码,您应该使用所有这些属性。

请注意,如果实体与一个或多个其他实体有关联,则其他实体的ID可能会合理地考虑到相等性测试。例如,您的Address实体可能会在Stateequals()次确认中包含其关联的hashCode()实体的ID。

答案 1 :(得分:0)

这取决于您的业务&#34;规则。在以下情况下,两个Address实例是等效的:

  • address1.streetline = address2.streetline
  • 和address1.city = address2.city
  • 和address1.postalcode = address2.postalcode
  • 和address1.state = address2.state

(例如,也许您还需要包含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;