2012-03-28 36 views
2

我有一個我需要實現以下約束的實體: 「對於列X和Y的任何組合,可能只有一條記錄,如果記錄的類型爲A,那麼列Z爲空。通過Hibernate驗證,我可以查詢被驗證的實體嗎?

最後一部分將其從簡單的唯一性約束轉變爲更復雜的東西。我正在編寫一個定製的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) 

有一點要注意的是,當這第一次插入完成表是空的。

問題是,我可以查詢我想驗證的同一張表嗎?這似乎是一個非常合乎邏輯的要求,因爲可以在類上添加約束註釋。我的驗證取決於數據的狀態。

+0

我不知道它是否在持久性事務中執行新的查詢查找? – 2012-03-28 13:29:59

+0

從休眠[論壇](https://forum.hibernate.org/viewtopic.php?f=1&t=1004374):「在任何回調方法中調用/使用同一個會話都是不好的。會話「。這可能是問題所在。 – 2012-03-28 14:41:29

回答

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,它工作的很好。

+0

謝謝你。我有一個類似的問題 - 沒有使用單獨的實體管理器,這意味着我的查詢內部驗證器只是掛起而沒有返回... – 2013-01-25 15:06:40

+0

@StefanHaberl我很高興這對某人有用。當我遇到這個問題時,其他人似乎沒有興趣。 – 2013-01-28 14:08:16