我遇到了一个奇怪的现象。在简化形式中,我的实体类看起来像这样:
@Entity
@Audited
public class Product {
@Id
@Column(length = 32)
private String id = IdGenerator.createId();
/** Descriptive texts, samples, comments etc.; ONIX composite Product/OtherText */
@OneToMany(fetch=FetchType.LAZY, cascade=CascadeType.ALL, orphanRemoval=true)
@JoinColumn(name="product_id")
@Index(name="idx_prod_text")
private Set<Text> texts;
...
}
@Entity
@Audited
public class Text {
@Id
@Column(length = 32)
private String id = IdGenerator.createId();
@NotNull
@Column(nullable=false, length=3)
private String type;
...
}
HashCode和equals在id字段上工作。
我已经建立了一个通用的预验证例程,用于以用户友好的方式自动校正和生成警告。对具有null类型的文本进行自动更正是从产品中的集合中删除此文本(通过调用product.getTexts().removeAll(entitiesToRemove)
)。
现在我得到了一个产品(以前从DB中读取,因此附加到Hibernate会话),它会附加一个类型为null的Text。它是自动更正的,如上所述,有问题的文本将从集合中删除。
到现在为止还挺好;在调试器中检查产品表明Text不再出现在文本集合中。但是当我打电话给productRepository.saveAndFlush(product)
()时,我得到了一个
javax.validation.ConstraintViolationException: Validation failed for classes [de.vlx.metadatastore.model.product.Text] during persist time for groups [javax.validation.groups.Default, ]
List of constraint violations:[
ConstraintViolationImpl{interpolatedMessage='darf nicht null sein', propertyPath=type, rootBeanClass=class de.vlx.metadatastore.model.product.Text, messageTemplate='{javax.validation.constraints.NotNull.message}'}
]
所以看来这个文本仍然由Hibernate验证?即使它从未出现在数据库中(当然也有NotNull约束),并且不再出现在产品的文本集合中了?
更奇怪的是:当我尝试通过在被删除实体的类型上设置虚拟值来修补此问题时,我没有得到上述异常,但是org.springframework.dao.DataIntegrityViolationException
抱怨类型为null的事实。
哪种魔法起作用,我该怎么做才能解决这个问题?
二手版本: Hibernate 4.1.7.Final Spring-data-jpa 1.6.0.RELEASE Spring-core 3.2.9.RELEASE
更新: 通过密集的调试,我最近发现,(因为产品以多种方式提供,如xml和excel文件,并且与当前版本的合并是一个相当复杂的过程),在这种情况下,以前版本的所有文本都被删除并且更新添加,然后在中央验证例程中删除错误文本。但是Hibernate已将添加存储在其动作队列中,并希望在删除之前执行插入。并且插入与初始(null)值一起存储,因此更新有问题的文本没有帮助。
我仍然完全无能为力。似乎我必须确保任何时候都没有无效对象可以输入任何集合,因为之后的修复无济于事。
答案 0 :(得分:1)
看起来你有两个选择:
NotNull
约束。当然第一种可能性更可取,因为我不确定设置伪文本是否会在删除语句之前触发更新语句。
更新: 我看到了托管实体问题的一些可能性(不需要这个,所以未经测试):
Text
刷新清理代码中的entityManager.refresh
个实体。这将发出选择,但应该避免这个问题。evict
吗?不知道冬眠会如何反应。Text
值,并将它们合并到服务方法中。我认为这是我的首选解决方案。答案 1 :(得分:0)
经过大量的调试和测试后,我终于找到了问题的原因和解决方法。
Hibernate确实保留了一个ActionQueue,其中保留了对托管实体的所有相关操作,并且主要按照它们在实体上完成的顺序。在我的情况下有例如两个Text对象添加到Product中的文本集合中,因此Hibernate在其ActionQueue中添加了一个InsertAction,其中包含插入时的值(因此后来修复实体确实没有效果,但是将UpdateAction添加到ActionQueue)。从集合中删除有缺陷的对象导致该对象的DeleteAction。
从不执行这些UpdateAction或DeleteAction,因为InsertAction失败并带有NotNull-Constraint。 所以我必须确保插入的对象永远不会有任何非法的空值。为此,我重构了验证服务,以便在之前插入具有可识别虚拟值的实体!= null,我稍后会用它来检查。不太好,但它确实有效。
我仍然对Hibernate ActionQueue的一种优化器感兴趣;从版本4.1.7开始实现了类似的东西吗?
特别感谢MartinFrey的一些有价值的建议。