使用Hibernate验证,我可以查询正在验证的实体吗?

时间:2012-03-28 13:00:59

标签: hibernate hibernate-validator

我有一个实体,我需要在其上实现以下约束: “列X和Y的任意组合可能只有一条记录,如果记录的类型为A,则Z列为空。”

最后一部分将其从简单的唯一性约束转变为更复杂的约束。我正在编写一个自定义的Hibernate验证器来检查它。

我正在做的是:

@Override
public boolean isValid(MyEntity value, ConstraintValidatorContext context) {
    Query query = DB.createQuery( // DB is just a convenience class
                "select count(*) from MyEntity" +
                "  where propertyX = :propertyX" +
                "    and propertyY = :propertyY" +
                "    and type = :type" +
                "    and propertyZ is null")
                .setParameter("propertyX", value.getPropertyZ())
                .setParameter("propertyY", value.getPropertyY())
                .setParameter("type", MyType.PRIMARY);

     return query.getResultList().size() <= 1;
}

如果有多个此类记录,则验证失败。这将强制在插入新条目之前始终设置propertyZ

然而这不起作用,因为此验证发生onPersist,此时查询返回带有null id的结果,这会导致异常。

以下是堆栈跟踪中的一些有趣的行:

[junit] org.hibernate.AssertionFailure: null id in my.package.MyEntity entry (dont flush the Session after an exception occurs)
[junit]     at org.hibernate.event.def.DefaultFlushEntityEventListener.checkId(DefaultFlushEntityEventListener.java:82)
[junit]     at org.hibernate.event.def.DefaultFlushEntityEventListener.getValues(DefaultFlushEntityEventListener.java:190)
[junit]     at org.hibernate.event.def.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:147)
[junit]     at org.hibernate.event.def.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:219)
[junit]     at org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:99)
[junit]     at org.hibernate.event.def.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:58)
[junit]     at org.hibernate.impl.SessionImpl.autoFlushIfRequired(SessionImpl.java:1185)
[junit]     at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1261)
[junit]     at org.hibernate.impl.QueryImpl.list(QueryImpl.java:102)
[junit]     at org.hibernate.ejb.QueryImpl.getResultList(QueryImpl.java:246)
[junit]     at my.package.validation.UniqueCombinationTypeValidator.isValid(UniqueCombinationTypeValidator.java:42)
[junit]     at my.package.validation.UniqueCombinationTypeValidator.isValid(UniqueCombinationTypeValidator.java:14)
[junit]     at org.hibernate.validator.engine.ConstraintTree.validateSingleConstraint(ConstraintTree.java:153)
[junit]     at org.hibernate.validator.engine.ConstraintTree.validateConstraints(ConstraintTree.java:140)
...
[junit]     at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:61)
[junit]     at org.hibernate.impl.SessionImpl.firePersist(SessionImpl.java:808)
[junit]     at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:782)
[junit]     at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:786)
[junit]     at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:672)
[junit]     at my.package.DB.persist(DB.java:278)
[junit]     at my.package.test.model.validation.UniqueCombinationTypeValidatorTest.testInsert(UniqueCombinationTypeValidatorTest.java:72)

另外需要注意的是,第一次插入完成后表格为空。

问题是,我可以查询我要验证的同一个表吗?这似乎是一个非常合乎逻辑的要求,因为约束注释可以放在类上。我的验证取决于数据的状态。

1 个答案:

答案 0 :(得分:3)

受到this post的启发以及it is never OK在会话触发的任何回调方法中调用/使用相同会话的知识,我设法通过抓住我的问题来解决问题EntityManagerFactory,这反过来让我得到EntityManager,这给了我一个新的Session。现在我可以使用它来进行查询。

EntityManager em = emFactory.createEntityManager();
session = (Session) em.getDelegate();
Query query = session.createQuery(...

注意:来自EntityManager docsgetDelegate()的内容是特定于实现的。我正在使用tomcathibernate,而且效果很好。