我有一个具有布尔值的实体,该值以“Y”或“N”字符的形式持久保存到数据库中:
union floatInt
{
float f;
unsigned int l;
};
floatInt A, B;
A.l = 0xFFA70B56;
B.f = A.f;
std::cout << std::hex << B.l << std::endl;
但是,当我尝试运行测试以将其保存到数据库时,我会得到一个 NULL for Constraint Violation error for activeIndicator ,尽管事实上我将其初始化为Boolean。正确,正如您在上面的代码中看到的那样。当我打开Hibernate的调试日志时,我能够验证它是否在insert语句中发送NULL 。以下是我的测试代码:
@Data
@Entity
@Table(name = "MYOBJECT", schema = "MYSCHEMA")
@EqualsAndHashCode(of = "id")
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class MyObject {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "MYOBJECT_SEQ")
@SequenceGenerator(name = "MYOBJECT_SEQ", sequenceName = "MYSCHEMA.MYOBJECT_SEQ")
private Long id;
@NotEmpty(message = "Name may not be empty")
@SafeHtml(whitelistType = WhiteListType.NONE, message = "Name may not contain html or javascript")
@Column(name = "NAME", nullable = false, length = 60)
private String name;
// Other fields...
@Type(type = "yes_no")
@Column(name = "ACTIVE", length = 1, nullable = false)
private Boolean isActive = Boolean.TRUE;
@SafeHtml(whitelistType = WhiteListType.NONE, message = "username may not contain html or javascript")
@Column(name = "USERNAME", nullable = false, length = 30)
private String username;
}
答案 0 :(得分:2)
事实证明,Hibernate不是故障,而是使用Lombok。如果您正在使用注释,例如 @Data , @EqualsAndHashCodeOf , @NoArgsConstructor , @AllArgsConstructor ,或 @Builder ,您的域对象可能正在使用Lombok。 (Groovy有一些类似的注释,只是检查你的导入是否使用 groovy.transform 或 lombok 作为包前缀)
导致我出现问题的代码位于我的测试类中:
MyObject.builder().name(NAME).username(USERNAME).build();
经过多次试验和错误后,很明显,当我的JPA / Hibernate设置正确时,初始化默认值为:
private Boolean activeIndicator = Boolean.TRUE;
没有被执行。
需要一些挖掘,但显然 Lombok的Builder不使用Java的初始化,但它自己的方法是创建对象。这意味着当您调用build()时,初始化默认值会被忽略,因此如果您未在构建器链中明确设置该字段,则该字段将保持为NULL。 请注意,正常的Java初始化和构造函数不受此影响;只有在使用Lombok的构建器创建对象时,问题才会出现。
详细说明这个问题的问题以及龙目岛关于他们为什么不能实施修复的解释详见:https://github.com/rzwitserloot/lombok/issues/663#issuecomment-121397262
有很多解决方法,您可能想要使用的解决方法取决于您的需求。
JPA PrePersist注释:如果您对默认值的要求是针对数据库约束的,并且您使用的是JPA或Hibernate,则可以使用此选项。该注释将在每次插入和更新实体之前运行它附加的方法,而不管它是如何初始化的。这很不错,因此您不必在两个地方设置默认值,就像您必须使用构建覆盖策略一样。我使用此选项,因为我的业务要求对此字段有强烈的默认要求。我将下面的代码添加到我的实体类来解决问题。我还删除了&#34; = Boolean.TRUE&#34;因为不再需要isActive字段声明的一部分。
@PrePersist
public void defaultIsActive() {
if(isActive == null) {
isActive = Boolean.TRUE;
}
}
答案 1 :(得分:0)
在具有默认值的字段上使用@ Builder.Deafult注释。