我想对@Unique
Bean Validation 有一个约束,但这不是标准提供的。如果我使用 JPA,@UniqueConstraint
我就没有独特的验证和错误报告机制。
有没有办法将其定义@Unique
为 Bean Validation 约束并将其与 JPA 结合,以便 JPA 创建具有唯一约束的列并检查值是否唯一?
我想对@Unique
Bean Validation 有一个约束,但这不是标准提供的。如果我使用 JPA,@UniqueConstraint
我就没有独特的验证和错误报告机制。
有没有办法将其定义@Unique
为 Bean Validation 约束并将其与 JPA 结合,以便 JPA 创建具有唯一约束的列并检查值是否唯一?
除非您在整个表上获得锁,否则基本上不可能使用 SQL 查询检查唯一性(任何并发事务都可以在手动检查之后但在正在进行的事务提交之前修改数据)。换句话说,不可能在 Java 级别实现有效的唯一验证,从而提供验证实现。检查唯一性的唯一可靠方法是在提交事务时。
BV 规范总结如下:
附录 D. Java Persistence 2.0 集成
问题:我们是否应该添加将映射到@Column(unique=true) 的@Unique?
@Unique 无法在 Java 级别可靠地测试,但可以生成数据库唯一约束生成。@Unique 今天不是 BV 规范的一部分。
因此,虽然我同意在 Bean Validation 异常中包含唯一(且非 null)约束违规会很好,但目前情况并非如此。
有关如何实现 @Unique 及其周围问题的更多信息,请参见此处 - http://community.jboss.org/wiki/AccessingtheHibernateSessionwithinaConstraintValidator
好吧,你可以做到,但这不是微不足道的。问题是:验证器需要数据库访问权限才能执行一些查询以检查您要插入的值是否已经存在。这不能从验证器中真正完成,因为它无权访问 sessionFactory/session。当然你可以在验证器中实例化它(session/sessionFactory),但这不是一个好的编码习惯。
您可以让验证器读取 JPA 注释并应用它。这是一个使用弹簧验证器的示例,可以用作扩展的想法。
您还可以在自定义验证器中注入(@Inject
或 Spring @Autowired
)您的会话 bean,并且容器应该知道如何连接它。我只知道这是一个 Spring 示例:
import javax.validation.ConstraintValidator;
public class MyConstraintValidator implements ConstraintValidator {
@Autowired //@Inject
private Foo aDependency;
...
}
您应该尝试(插入或更新),捕获异常并执行一些操作。例如在 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();
}
另一种选择是在插入/修改之前检查。这可能会很耗时,并且不会阻止错误最终发生。