In terms of creating a JPA Entity what should and should not go into a equals and hashcode. As an example I have an Address entity as follows.
I've read that the ID should not be included, but not sure why. What about nested objects like State in my case? I did not include locations because State is the non owning end, Location owns the relationship.
Of the following class what should and should not be in the equals and 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;
}
}
The recommendation I have seen most is that equality for entities should reflect the appropriate sense of equality for your business logic, as opposed to your persistence logic. If you are using surrogate IDs rather than natural IDs, as is normal with JPA, then that means that you do not base entities' equality on their IDs.
Consider: suppose you load an Address
entity from the database, and you also construct one based on data provided via the application UI. If you want there to be any possibility that they test as equals()
each other, then you must base that test only on properties other than the ID, because the latter object does not yet have any ID assigned. It's up to you which properties should contribute to that test.
Of course, if ever you override equals()
then you should override hashCode()
as well to ensure the invariant that any two objects that test equals()
each other have the same hash code. To do so, you may use only properties that contribute to the equality test in the hash code computation, and for the most distinguishing hash code you should use all such properties.
Note that where an entity has an association with one or more other entities, the IDs of the other entities may reasonably factor into the equality test. For example, your Address
entity might include the ID of its associated State
entity in its equals()
and hashCode()
determinations.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With