在Hibernate验证期间执行EntityManager查询的正确方法

我有点Java EE / EJB菜鸟,但是从我收集的文档和其他文章中,您不能在实体验证期间使用相同的entitymanager /session查询数据库。

通常,便携式应用程序的生命周期方法不应调用EntityManager或Query操作,访问其他实体实例或在同一持久性上下文内修改关系。[43]

生命周期回调方法可以修改在其上调用它的实体的非关系状态。

请翻译?

这是非常抽象的……可以用更具体的术语来解释吗?它导致的问题多于答案。例如,如果我的实体有一个延迟加载的集合,是否可以在验证期间访问它?该集合是“另一个实体”,将需要进行数据库查询,这似乎违反了文档。

这种“生命周期要求”似乎很奇怪,因为某些验证确实确实需要查询数据库,这只是生活中的事实。

从其他帖子中,我还看到人们通过使用Entitymanagerfactory创建新的entitymanager /会话来解决此查询问题。

这使我想到两个有关使用EntityManagers和Hibernate Validation的问题:

  1. 我是否可能存在某种设计缺陷,或者因为在验证过程中需要查询数据库而滥用了Hibernate Validation?
  2. 鉴于我将Java EE与JBoss结合使用,如何将验证器注入EntityManagerFactory?

我已经尝试过这样的事情:

    @Stateless

public class UserValidator implements ConstraintValidator<ValidUser, User> {

@PersistenceUnit(unitName="blahblah")

EntityManagerFactory emf;

...

}

但是EMF永远不会被注入。我猜@Stateless标记变得无关紧要,因为我正在实现ConstraintValidator接口,这对于HibernateValidator起作用是必需的。

那么从验证器获取EntityManagerFactory的一般模式是什么?

谢谢!

回答:

通过一些评论和足够的探讨,我终于找到了某种“规范”的方式来回答我的问题。

但是要弄清楚,我的问题确实是在问两件事,它们有两个不同的答案:

  1. 您如何将事物注入到Hibernate Validation框架中使用的Validator中?
  2. 假设我们可以注入事物,那么在JPA生命周期事件中注入EntityManagerFactory或EntityManager并将其用于查询是否安全?

首先我要简单回答第二个问题,强烈建议在验证过程中使用第二个EntityManager进行查询。这意味着您应该注入一个EntityManagerFactory并为查询创建一个新的EntityManager(而不是注入一个与创建生命周期事件的实体相同的EntityManager)。

一般来说,出于验证目的,您无论如何都只会查询数据库,而不会插入/更新,因此这样做相当安全。

现在回答问题1。

是的,完全有可能将事物注入到HibernateValidation框架中使用的Validator中。为此,您需要做三件事:

  1. 创建一个自定义ConstraintValidatorFactory,它将创建框架中使用的验证器(覆盖Hibernate的默认工厂)。(我的示例使用JavaEE,而不是Spring,所以我使用BeanManager,但在Spring中,您可能会为此使用ApplicationContext。)
  2. 创建一个validate.xml文件,该文件告诉HibernateValidation框架将哪个类用于ConstraintValidatorFactory。确保此文件最终出现在您的类路径中。
  3. 编写一个注入器的验证器。

这是使用“托管”(可注入)验证器的示例自定义ConstraintValidatorFactory:

package com.myvalidator;

public class ConstraintInjectableValidatorFactory implements ConstraintValidatorFactory {

private static BeanManager beanManager;

@SuppressWarnings(value="unchecked")

@Override

public <T extends ConstraintValidator<?, ?>> T getInstance(Class<T> clazz) {

// lazily initialize the beanManager

if (beanManager == null) {

try {

beanManager = (BeanManager) InitialContext.doLookup("java:comp/BeanManager");

} catch (NamingException e) {

// TODO what's the best way to handle this?

throw new RuntimeException(e);

}

}

T result = null;

Bean<T> bean = (Bean<T>) beanManager.resolve(beanManager.getBeans(clazz));

// if the bean/validator specified by clazz is not null that means it has

// injection points so get it from the beanManager and return it. The validator

// that comes from the beanManager will already be injected.

if (bean != null) {

CreationalContext<T> context = beanManager.createCreationalContext(bean);

if (context != null) {

result = (T) beanManager.getReference(bean, clazz, context);

}

// the bean/validator was not in the beanManager meaning it has no injection

// points so go ahead and just instantiate a new instance and return it

} else {

try {

result = clazz.newInstance();

} catch (Throwable t) {

throw new RuntimeException(t);

}

}

return result;

}

}

这是一个示例validation.xml文件,该文件告诉Hibernate Validator哪个类用作ValidatorFactory:

<?xml version="1.0" encoding="UTF-8"?>

<validation-config

xmlns="http://jboss.org/xml/ns/javax/validation/configuration"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://jboss.org/xml/ns/javax/validation/configuration validation-configuration-1.0.xsd">

<constraint-validator-factory>

com.myvalidator.ConstraintInjectableValidatorFactory

</constraint-validator-factory>

</validation-config>

最后是带有注入点的验证器类:

public class UserValidator implements ConstraintValidator<ValidUser, User> {

@PersistenceUnit(unitName="myvalidator")

private EntityManagerFactory entityManagerFactory;

private EntityManager entityManager;

@Override

public void initialize(ValidUser annotation) {

}

@Override

public boolean isValid(User user, ConstraintValidatorContext context) {

// validation takes place during the entityManager.persist() lifecycle, so

// here we create a new entityManager separate from the original one that

// invoked this validation

entityManager = entityManagerFactory.createEntityManager();

// use entityManager to query database for needed validation

entityManager.close();

}

}

以上是 在Hibernate验证期间执行EntityManager查询的正确方法 的全部内容, 来源链接: utcz.com/qa/409304.html

回到顶部