JPA 和 Bean 验证的唯一约束

发布于 2024-09-14 17:38:09 字数 195 浏览 13 评论 0原文

我希望 Bean Validation 有一个 @Unique 约束,但这不是标准提供的。如果我使用 JPA 的 @UniqueConstraint 我就不会有独特的验证和错误报告机制。

有没有办法将@Unique定义为Bean验证约束并将其与JPA结合起来,以便JPA创建具有唯一约束的列并检查值是否唯一?

I'd like to have a @Unique constraint with Bean Validation, but that is not provided by the standard. If I would use JPA's @UniqueConstraint I wouldn't have a unique validation and error reporting mechanism.

Is there a way to define @Unique as a Bean Validation constraint and combine it with JPA, such that JPA creates a column with an unique constraint and checks wheter a value is unique or not?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

遥远的她 2024-09-21 17:38:09

除非获得整个表的锁,否则基本上不可能使用 SQL 查询检查唯一性(任何并发事务都可以在手动检查之后但在正在进行的事务提交之前修改数据) 。换句话说,不可能在 Java 级别实现有效的唯一验证,从而提供验证实现。检查唯一性的唯一可靠方法是在提交事务时。

BV 规范总结如下:

附录 D. Java Persistence 2.0 集成

问题:我们是否应该添加@Unique
会映射到@Column(unique=true)?

@Unique 无法在 Java 上进行测试
水平可靠,但可以产生
数据库唯一约束生成。
@Unique 不是 BV 规范的一部分
今天。

因此,虽然我同意将唯一(且非空)约束违规包含在 Bean 验证异常中会很好,但目前情况并非如此。

参考

Unless you acquire a lock on a whole table, it is basically not possible to check for unicity using a SQL query (any concurrent transaction could modify data after a manual check but before the commit of the ongoing transaction). In other words, it isn't possible to implement a valid unique verification at the Java level and thus to provide a validation implementation. The only reliable way to check for unicity is while committing the transaction.

The BV spec summarizes it like this:

Appendix D. Java Persistence 2.0 integration

Question: should we add @Unique that
would map to @Column(unique=true)?

@Unique cannot be tested at the Java
level reliably but could generate a
database unique constraint generation.
@Unique is not part of the BV spec
today.

So while I agree that it would be nice to have unique (and non null) constraint violations wrapped in a Bean Validation exception, this is currently not the case.

References

丑丑阿 2024-09-21 17:38:09

有关如何实现 @Unique 及其周围问题的更多信息可以在这里找到 - http://community。 jboss.org/wiki/AccessingtheHibernateSessionwithinaConstraintValidator

More information on how to implement a @Unique and the problematic around it can be found here - http://community.jboss.org/wiki/AccessingtheHibernateSessionwithinaConstraintValidator

琴流音 2024-09-21 17:38:09

好吧,你可以做到,但这并不是一件小事。问题是:验证器需要访问数据库来执行一些查询来检查您要插入的值是否已经存在。这实际上不能从验证器完成,因为它无权访问 sessionFactory/会话。当然,您可以在验证器内实例化它(session/sessionFactory),但这不是一个好的编码实践。

Well you CAN do it, but it's not trivial. The problem is: the validator requires database access to perform some queries to check, if the value you want to insert is already there or not. And this can't be really done from the validator, as it doesn't have access to the sessionFactory/session. Of course you could instantiate it (session/sessionFactory) inside the validator, but it's not a good coding practice.

非要怀念 2024-09-21 17:38:09

您可以让验证器读取 JPA 注释并应用它。这是一个使用 spring 验证器的示例,可以用作扩展的想法。

JPA JSR303 Spring表单验证

你也可以注入(@Inject 或 Spring 的 @Autowired)自定义验证器中的会话 bean 和容器应该知道如何连接它。我只知道这是一个Spring的例子:

import javax.validation.ConstraintValidator;

public class MyConstraintValidator implements ConstraintValidator {

@Autowired //@Inject
private Foo aDependency;

...
}

You can make a validator read the JPA annotations and apply it. Here is somewhat of an example using spring validators that can be used as an idea to expand on.

JPA JSR303 Spring Form Validation

You can also inject (@Inject or Spring's @Autowired) your session bean in a custom validator and the container should know how to wire it up. I only know this as a Spring example:

import javax.validation.ConstraintValidator;

public class MyConstraintValidator implements ConstraintValidator {

@Autowired //@Inject
private Foo aDependency;

...
}
十二 2024-09-21 17:38:09

您应该尝试(插入或更新),捕获异常并执行一些操作。例如,在 JSF 支持 bean 中:

try {
   dao.create(record);//or dao.modify(record)
   //add message success
} catch(EJBException e) {
   //look for origin of error (duplicate label, duplicate code, ...)
   var err = dao.isUnique(record);
   if(err == null) throw e;//other error
   String clientId = null;
   String message = null;
   switch(err) {
      case CODE:
        clientId = "client_id_of_input_code";
        message = "duplicate code";
        break;
      case LABEL:
        clientId = "client_id_of_input_label";
        message = "duplicate label";
        break;
      default:
        throw new AssertionError();//or something else
   }
   facesContext.addMessage(clientId, new FacesMessage(FacesMessage.SEVERITY_ERROR, message));
   facesContext.validationFailed();
}

另一个选项是在插入/修改之前进行检查。这可能非常耗时,并且不能防止错误最终发生。

You should try (insert or update), catch the exception and do some action. For example in a JSF backing bean :

try {
   dao.create(record);//or dao.modify(record)
   //add message success
} catch(EJBException e) {
   //look for origin of error (duplicate label, duplicate code, ...)
   var err = dao.isUnique(record);
   if(err == null) throw e;//other error
   String clientId = null;
   String message = null;
   switch(err) {
      case CODE:
        clientId = "client_id_of_input_code";
        message = "duplicate code";
        break;
      case LABEL:
        clientId = "client_id_of_input_label";
        message = "duplicate label";
        break;
      default:
        throw new AssertionError();//or something else
   }
   facesContext.addMessage(clientId, new FacesMessage(FacesMessage.SEVERITY_ERROR, message));
   facesContext.validationFailed();
}

Another option is to check before the insertion/modification. This can be time consuming and doesn't prevent the error to happen in the end.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文