【问题标题】:Gracefully handling ConstraintValidationExceptions in Hibernate在 Hibernate 中优雅地处理 ConstraintValidationExceptions
【发布时间】:2012-07-09 08:54:28
【问题描述】:

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

  • 我想利用 Javax(和 Hibernate)的验证注释,
  • 我想更正或丢弃无效对象,
  • 我想利用 javax 的 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 挂钩的 save 之前手动运行(可维护性噩梦!)。

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

【问题讨论】:

  • 在什么情况下您希望保存一些对象而不是放弃整个事务?

标签: java mysql hibernate persistence


【解决方案1】:

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

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

【讨论】:

  • 基本上我宁愿不在多个地方保留验证代码。这些字段不是由用户设置的,而是一系列处理算法,都相似,但有一些小的变体。我会阅读验证组,也许这就是诀窍!
【解决方案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 中的任何内容都不会被验证。

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

validator.validate(object);

因此所有组都将被验证。

【讨论】:

  • 太棒了,@Matt。 Affe 在验证组中暗示你为我做了功课。 :) 我会尝试一下。使用验证组预先筛选会破坏保存并导致事务失败的事情,让其余的验证(和 PrePersist 方法等)在保存时被调用。
  • NP。我对框架非常熟悉。我经常使用它,并且遇到了这个确切的问题。我们在同一个事务中保存了多个对象,因此预先验证允许我们只保存那些通过验证的对象,并且我们可以记录任何失败的对象。同时我们使用 HibernateInterceptor 来填充时间戳(我们还没有使用 JPA,所以 PrePersist 和 PreUpdate 对我们来说不容易使用)。
猜你喜欢
  • 2011-08-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-30
  • 2011-11-26
相关资源
最近更新 更多