在我们的Hibernate项目中,实体是使用Javabeans模式编码的。在我们的代码中有很多地方,有人忘记设置一个mutator,我们得到了一个由于NOT NULL约束的异常。有没有人使用构建器来构建他们的实体,或者让它们变得不可变?我试图找到一种有效的模式,它不属于Javabeans模式的风格。
NOT NULL
u3r8eeie1#
如果你让你的bean不可变,那么你必须使用字段级访问,这带来了它自己的一系列问题,正如here所讨论的那样。我们采取的方法是让一个Builder/Factory为我们执行/验证需求等规则。
yqyhoc1h2#
在我们的项目中,我们确实使用了香草构建器方法(@see Effective Java)。请考虑以下示例:
@Entity public class Person { public static class Builder { private String firstName; private String lastName; private PhoneNumber phone; public Builder() {} public Builder withFullName(String fullName) { Preconditions.notNull(fullName); String[] split = fullName.split(" "); if (split == null || split.length != 2) { throw new IllegalArgumentException("Full name should contain First name and Last name. Full name: " + fullName); } this.firstName = split[0]; this.lastName = split[1]; return this; } public Builder withPhone(String phone) { // valueOf does validation this.phone = PhoneNumber.valueOf(phone); return this; } public Person build() { return new Person(this); } } //@Columns private long id;//@Id private String firstName; private String lastName; private String phoneNumber; // hibernate requires default constructor private Person() {} private Person(Builder builder) { this.firstName = Preconditions.notNull(builder.firstName); this.lastName = Preconditions.notNull(builder.lastName); this.phoneNumber = builder.phone != null ? builder.phone : null; } //Getters @Nonnull public String getFirstName() { return firstName;} @Nonnull public String getLastName() { return lastName;} @Nullable public String getPhoneName() { return phone;} public long getId() { return id;} }
如果你有时想改变实体,我建议引入new Builder(Person person),它会复制所有数据,所以你可以用builder改变它。当然,它会产生一个新的实体,所以旧的实体仍然是只读的。使用(带有突变)就像这样简单:
new Builder(Person person)
Person.Builder personBuilder = new Person.Builder(); Person person = personBuilder.withFullName("Vadim Kirilchuk").withPhone("12345678").build(); Person modified = new Person.Builder(person).withPhone("987654321").build();
同样重要的是要注意,在这个例子中,Person不是100%不可变的(也不能是)类:首先,因为id将由jpa设置,也可能在运行时获取惰性关联,最后,因为你不能有字段final(由于需要默认构造函数):(后一点也是多线程环境的问题,即在#build()之后传递给另一个线程实体可能会导致各种错误,因为另一个线程不能保证看到完全构造的对象。JPA 2.1规范的“2.1实体类”一节中说:实体类的方法或持久示例变量都不能是final。还有一个类似的方法:http://vlkan.com/blog/post/2015/03/21/immutable-persistence/在我的情况下,我只会添加id到建设者,而不是建设服务的顶部草案..
x6492ojm3#
@Immutable注解可以用于实体。JPA将忽略对实体的所有更新。https://docs.jboss.org/hibernate/orm/5.2/javadocs/org/hibernate/annotations/Immutable.html
@Immutable
3条答案
按热度按时间u3r8eeie1#
如果你让你的bean不可变,那么你必须使用字段级访问,这带来了它自己的一系列问题,正如here所讨论的那样。我们采取的方法是让一个Builder/Factory为我们执行/验证需求等规则。
yqyhoc1h2#
在我们的项目中,我们确实使用了香草构建器方法(@see Effective Java)。请考虑以下示例:
如果你有时想改变实体,我建议引入
new Builder(Person person)
,它会复制所有数据,所以你可以用builder改变它。当然,它会产生一个新的实体,所以旧的实体仍然是只读的。使用(带有突变)就像这样简单:
同样重要的是要注意,在这个例子中,Person不是100%不可变的(也不能是)类:首先,因为id将由jpa设置,也可能在运行时获取惰性关联,最后,因为你不能有字段final(由于需要默认构造函数):(后一点也是多线程环境的问题,即在#build()之后传递给另一个线程实体可能会导致各种错误,因为另一个线程不能保证看到完全构造的对象。
JPA 2.1规范的“2.1实体类”一节中说:
实体类的方法或持久示例变量都不能是final。
还有一个类似的方法:http://vlkan.com/blog/post/2015/03/21/immutable-persistence/
在我的情况下,我只会添加id到建设者,而不是建设服务的顶部草案..
x6492ojm3#
@Immutable
注解可以用于实体。JPA将忽略对实体的所有更新。https://docs.jboss.org/hibernate/orm/5.2/javadocs/org/hibernate/annotations/Immutable.html