gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-04 08:10:20 25 4
gpt4 key购买 nike

我是一个 Java EE/EJB 菜鸟,但是从我收集的文档和其他帖子中,您无法在实体验证期间使用相同的 entitymanager/session 查询数据库。

In general, the lifecycle method of a portable application should not invoke EntityManager or Query operations, access other entity instances, or modify relationships within the same persistence context.[43] A lifecycle callback method may modify the non-relationship state of the entity on which it is invoked.



请问翻译?

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

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

从其他帖子中,我还看到人们通过使用 entitymanagerfactory 创建一个新的实体管理器/ session 来解决这个查询问题。

这让我想到了两个关于使用 EntityManagers 和 Hibernate Validation 的问题:
  • 是否有可能我有某种设计缺陷或滥用 Hibernate 验证,因为我需要在验证期间查询数据库?
  • 鉴于我在 JBoss 中使用 Java EE,我如何使用 EntityManagerFactory 注入(inject)我的 validator ?

  • 我试过这样的事情:
    @Stateless
    public class UserValidator implements ConstraintValidator<ValidUser, User> {
    @PersistenceUnit(unitName="blahblah")
    EntityManagerFactory emf;

    ...
    }

    但是 EMF 永远不会被注入(inject)。我猜@Stateless 标签变得无关紧要,因为我正在实现一个 ConstraintValidator 接口(interface),这是 Hibernate Validator 工作所必需的。

    那么从 Validator 获取 EntityManagerFactory 的一般模式是什么?

    谢谢!

    最佳答案

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

    但为了澄清问题,我的问题实际上是问两件事,它们有两个不同的答案:

  • 你如何将东西注入(inject)到 Hibernate Validation 框架中使用的 Validator 中?
  • 假设我们可以注入(inject)东西,注入(inject) EntityManagerFactory 或 EntityManager 并在 JPA 生命周期事件期间使用它们进行查询是否安全?

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

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

    我问了一个非常相关的 SO 问题 here .

    现在回答问题1。

    是的,完全可以将东西注入(inject) Hibernate Validation 框架中使用的 Validators 中。要做到这一点,你需要做 3 件事:
  • 创建一个自定义的 ConstraintValidatorFactory,它将创建框架中使用的 validator (覆盖 Hibernate 的默认工厂)。 (我的示例使用 Java EE,而不是 Spring,所以我使用 BeanManager,但在 Spring 中您可能会为此使用 ApplicationContext)。
  • 创建一个validation.xml 文件,它告诉Hibernate Validation 框架为ConstraintValidatorFactory 使用哪个类。确保此文件最终位于您的类路径中。
  • 编写一个注入(inject)一些东西的 validator 。

  • 这是一个使用“托管”(可注入(inject)) validator 的自定义 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>

    最后是一个带有注入(inject)点的 validator 类:
    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 - 在 hibernate 验证期间执行 EntityManager 查询的正确方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18267269/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com