使用Hibernate验证,我可以查询正在验证的实体吗? [英] With Hibernate validation, can I query the entity being validated?

查看:48
本文介绍了使用Hibernate验证,我可以查询正在验证的实体吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个实体,需要在其上实施以下约束: 对于X和Y列的任何组合,可能永远只有一条记录,如果记录的类型为A,则Z列为空."

I have an entity on which I need to implement the following constraint: "There may only ever be one record for any combination of columns X and Y, for which column Z is null if the record is of type A."

最后一部分将其从简单的唯一性约束转换为更复杂的约束.我正在编写一个自定义的Hibernate验证程序来对其进行检查.

The last part turns this from a simple uniqueness constraint to something more complex. I'm writing a custom Hibernate validator to check it.

我正在做的是:

@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.

If there is more than one such record the validation should fail. This will enforce always setting propertyZ before inserting a new entry.

但是不起作用,因为此验证发生在onPersist上,此时查询返回的结果带有null id,这会导致异常.

However this does not work because this validation happens onPersist and at that point the query returns a result with a null id, which causes an exception.

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

Here are some interesting lines from the stack trace:

[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)


要注意的另一件事是,第一次完成插入后,该表为空.


One other thing to note is that the table is empty when this first insert is done.

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

THE QUESTION IS, can I query the same table that I am trying to validate? It seems like a very logical requirement, since a constraint annotation can be put on the class. My validation is dependent on the state of the data.

推荐答案

灵感来自这永远都不行的认识在该会话触发的任何回调方法中调用/使用同一会话,我设法简单地通过握住我的EntityManagerFactory来解决问题,这反过来又让我得到了EntityManager,给我一个新的Session.现在,我可以用它来进行查询.

Inspired by this post and the knowledge that it is never OK to call/use the same session in any callback methods that are triggered from the session, I managed to solve the problem quite simply by getting hold of my EntityManagerFactory, which in turn lets me get an EntityManager, which gives me a new Session. Now I can use this to do the query.

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

注意:来自 EntityManager文档getDelegate()是特定于实现的.我正在使用tomcathibernate,效果很好.

NOTE: That from the EntityManager docs, getDelegate() is implementation specific. I'm using tomcat and hibernate, and it work's well.

这篇关于使用Hibernate验证,我可以查询正在验证的实体吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆