2

SOには、Hibernate検証の実行、例外のキャッチなどに関連する投稿がたくさんあります。しかし、それらのすべては、以下に説明する状況でのいくつかの非常に理想的でない設計の選択に私を反対させました。これは、クリーンな解決策がないとは信じられないほど一般的な状況のようです。

  • Javax(およびHibernate)の検証アノテーションを活用したいのですが、
  • 無効なオブジェクトを修正または破棄したい、
  • javaxのPrePersistなどのアノテーションを利用して、オブジェクトに対する反復アクションまたは時間ベースのアクションを処理したいと思います。

3つを一緒に使用することはうまくいかないようです。

  • 例外が発生すると、 Hibernateはトランザクションをコミットできません。無効なオブジェクトがあると、制約違反の例外が発生します。ConstraintViolationExceptionがこれに含まれているのか、それとも特殊なケース[1]として扱われているのか、正式に見つけることはできませんが...

  • ConstraintViolationExceptionをキャッチして次のオブジェクトに移動すると続行できるようですが、(データベースによって)IDが割り当てられていないオブジェクトがあるため、トランザクションをフラッシュまたはコミットしようとするとHibernateが文句を言います。

    • オブジェクトをnullに設定しようとしたり、session.evict(myObject)を使用しても、Hibernateがオブジェクトについて持っている知識を「破る」ことに成功しないことを考えました。
  • 保存する前に[検証を「手動で」実行]することができます(http://docs.jboss.org/hibernate/stable/validator/reference/en-US/html_single/#d0e2697)。 2回実行される-これはばかげているように見えますが、@ 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]:それは不器用なリファレンスだと知っていますが、私はそれを再び見つけることができないほど多くの読書をしてきました。誰かがより技術的な詳細で、どのエラーがトランザクションを無効にするのか、回復可能にするのかを明確にしてくれると嬉しいです。

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);

この時点で、デフォルトの検証グループ(ちなみに、「groups」属性を空白のままにした場合に使用されるもの)でマークされたフィールドのみが検証されます。PersistValidationGroup内のすべてが検証されません。

ただし、休止状態は次のように呼び出されます。

validator.validate(object);

したがって、すべてのグループが検証されます。

于 2012-07-10T02:24:47.897 に答える