我已经使用JPA(实现休眠)一段时间了,每次我需要创建实体时,我都会遇到诸如AccessType,不可变属性,equals / hashCode等问题。
因此,我决定尝试找出每个问题的最佳常规做法,并写下来供个人使用。
但是,我不介意让任何人对此发表评论或告诉我我错了。
实体类
实现可序列化
原因:规范要求您必须这样做,但是某些JPA提供程序没有强制执行此操作。作为JPA提供程序的Hibernate不会强制执行此操作,但是如果尚未实现Serializable,它可能会因ClassCastException失败而失败。
建设者
用实体的所有必填字段创建一个构造函数
原因:构造函数应始终使创建的实例保持健全状态。
除了这个构造函数:还拥有一个包私有的默认构造函数
原因:Hibernate需要默认构造函数来初始化实体;允许使用private,但是在没有字节码检测的情况下,包私有(或公共)可见性对于运行时代理生成和有效的数据检索是必需的。
字段/属性
在一般情况下使用字段访问,在需要时使用属性访问
原因:这可能是最有争议的问题,因为没有明确的,令人信服的论点(财产使用权与实地使用权);但是,由于更清晰的代码,更好的封装并且无需为不可变字段创建设置器,因此字段访问似乎是普遍喜欢的方法
省略不可变字段的设置器(访问类型字段不需要)
- 属性可能是私有的
原因:我曾经听说保护(Hibernate)的性能更好,但是我在网上可以找到的是:Hibernate可以直接访问公共,私有和受保护的访问器方法,以及公共,私有和受保护的字段。 。选择取决于您,您可以将其匹配以适合您的应用程序设计。
等于/哈希码
- 如果仅在持久化实体时设置此ID,请不要使用生成的ID
- 根据喜好:使用不可变值形成唯一的业务密钥,并使用它来测试是否相等
- 如果唯一的业务密钥不可用,则使用在初始化实体时创建的非临时UUID;有关更多信息,请参见这篇出色的文章。
- 从不引用相关实体(ManyToOne);如果此实体(如父实体)需要成为业务密钥的一部分,则仅比较ID。只要使用属性访问类型,在代理上调用getId()不会触发实体的加载。
实体实例
@Entity
@Table(name = "ROOM")
public class Room implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue
@Column(name = "room_id")
private Integer id;
@Column(name = "number")
private String number; //immutable
@Column(name = "capacity")
private Integer capacity;
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "building_id")
private Building building; //immutable
Room() {
// default constructor
}
public Room(Building building, String number) {
// constructor with required field
notNull(building, "Method called with null parameter (application)");
notNull(number, "Method called with null parameter (name)");
this.building = building;
this.number = number;
}
@Override
public boolean equals(final Object otherObj) {
if ((otherObj == null) || !(otherObj instanceof Room)) {
return false;
}
// a room can be uniquely identified by it's number and the building it belongs to; normally I would use a UUID in any case but this is just to illustrate the usage of getId()
final Room other = (Room) otherObj;
return new EqualsBuilder().append(getNumber(), other.getNumber())
.append(getBuilding().getId(), other.getBuilding().getId())
.isEquals();
//this assumes that Building.id is annotated with @Access(value = AccessType.PROPERTY)
}
public Building getBuilding() {
return building;
}
public Integer getId() {
return id;
}
public String getNumber() {
return number;
}
@Override
public int hashCode() {
return new HashCodeBuilder().append(getNumber()).append(getBuilding().getId()).toHashCode();
}
public void setCapacity(Integer capacity) {
this.capacity = capacity;
}
//no setters for number, building nor id
}
欢迎添加到此列表的其他建议...
更新
自阅读本文以来,我已经调整了实现eq / hC的方式:
- 如果有一个不变的简单业务密钥可用:
- 在所有其他情况下:使用uuid
final
(根据您对设置员的遗漏来判断,我想您也是如此)。
notNull
来的?