2

SO 和其他站点上有很多与执行 Hibernate 验证、捕获异常等相关的帖子。然而,所有这些都让我在下面描述的情况下遇到了一些非常不理想的设计选择。这似乎是一种常见的情况,我不敢相信没有一个干净的解决方案。

  • 我想利用 Javax(和 Hibernate)的验证注释,
  • 我想纠正或丢弃无效的对象,
  • 我想利用 javax 的 PrePersist 等注释来处理对我的对象的重复或基于时间的操作。

三个一起使用似乎并不奏效。

  • 当发生异常时,Hibernate 不会让您提交事务。只要我有一个无效的对象,我就会得到一个违反约束的异常。我无法权威地找到ConstraintViolationException是否包含在其中,或者被视为特殊情况[1],但是......

  • 如果我捕捉到 ConstraintViolationException 并继续处理下一个对象,我似乎能够继续,但是当我尝试刷新或提交事务时,Hibernate 会抱怨,因为我有没有(由数据库分配)id 的对象

    • 我曾想过尝试将对象设置为 null 或使用session.evict(myObject)来“破坏”Hibernate 对该对象的了解。
  • 在尝试保存之前,我可以 [“手动”运行验证](http://docs.jboss.org/hibernate/stable/validator/reference/en-US/html_single/#d0e2697),但要付出代价被执行了两次——这看起来很傻,但这并没有调用 @PrePersist 钩子,导致错误的违规行为。

一个人做什么?

具体来说,我有很多(10,000 多个)对象,其中一小部分总是无效的。

@Entity
public class myPojo implements Serializable {

  @Id
  @GeneratedValue
  private long id;

  @NotBlank
  private String anotherString;

  @NotNull
  @Temporal(TemporalType.TIMESTAMP)
  private Date createdAt;

  @NotNull
  @Temporal(TemporalType.TIMESTAMP)
  private Date updatedAt;  

  @NotNull
  @Temporal(TemporalType.TIMESTAMP)
  private Date postedDate;  

  @PrePersist
  protected void onPrePersist() {
    this.createdAt = new Date();
    this.updatedAt = this.createdAt;
    if (this.postedDate == null)
      this.postedDate = this.createdAt;
  }
}

我想保存这个函数,并捕获任何违反约束的对象:

void saveResource(MyPojo myPojp) {
  try {
    session.saveOrUpdate(mypojo);
  }
  catch (final ConstraintViolationException ex) {
     System.err.println("Could not save " + myPojo + " because " +
        this.getValidationErrors(myPojo));
  }
}

其中 getValidationErrors() 返回通过手动创建和使用验证工厂找到的所有ConstraintViolation的字符串。

我知道的唯一其他可能性是围绕每次保存执行单个事务(这似乎是个坏主意,因为如果确实发生真正的异常,我不希望任何项目持续存在)或者可能编写自定义验证器以手动运行在我调用保存之前调用 prepersist 钩子(可维护性的噩梦!)。

[1]:我知道这是一个糟糕的参考,但我读了这么多书,我再也找不到了。希望有人能在更多技术细节中澄清哪些错误导致交易无效与可恢复。

4

2 回答 2

3

想法 1:为什么将应用程序级别的验证注释放在 PrePersist 中您自己管理的字段上,这些字段不是由用户设置的?

想法2:您可以使用验证组,以便您可以仅预先检查在用户级别设置的那些字段并忽略系统管理的字段。

于 2012-07-09T22:29:50.370 回答
2
  public interface PersistValidationGroup { }


  @NotBlank
  private String anotherString;

  @NotNull(groups={PersistValidationGroup.class})
  @Temporal(TemporalType.TIMESTAMP)
  private Date createdAt;

  @NotNull(groups={PersistValidationGroup.class})
  @Temporal(TemporalType.TIMESTAMP)
  private Date updatedAt;  

  @NotNull(groups={PersistValidationGroup.class})
  @Temporal(TemporalType.TIMESTAMP)
  private Date postedDate;  

然后,当您手动验证时:

validator.validate(object, javax.validation.groups.Default.class);

此时,只有那些标有默认验证组的字段(顺便说一下,如果您将“组”属性留空,则使用该组)将被验证。PersistValidationGroup 中的任何内容都不会被验证。

但是,我相信休眠会这样调用:

validator.validate(object);

因此,所有组都将被验证。

于 2012-07-10T02:24:47.897 回答