2

各プロパティのset()メソッドでHibernateにフィールド長の制約を検証させる簡単な方法はありますか?

後で例外が発生するのを待つのではなく、フィールドに無効な値が含まれるのを防ぎたい。

Usernameプロパティを持つクラスがあります:

@Column(name = "username", length = 12)
public String getUsername()
{
    return this.username;
}

public void setUsername(String username)
{
    this.username = username;
}

Hibernateテンプレートを変更して、次のようにset()メソッドを作成できます。

@Column(name = "username", length = 12)
public String getUsername()
{
    return this.username;
}

public void setUsername(String username)
{
    Method m = ClassWithUsername.getDeclaredMethod("setUsername");
    javax.persistence.Column col = m.getAnnotation(javax.persistence.Column.class);
    int maxLen = col.length();

    // Validate the field length 
    if(username!=null && username.length() > maxLen)
        throw Exception("Username must be no more than " + maxLen + " characters.");

    this.username = username;
}

これを行う前に、他のアプローチがあるかどうか疑問に思っています。

4

2 に答える 2

1

Bean Validationを使用してみませんか?? http://docs.jboss.org/hibernate/annotations/3.5/reference/en/html_single/を参照してください。

Column アノテーションの長さ属性は、以下を指定するために使用されます。 列の長さ。(文字列値の列が使用されている場合にのみ適用されます。)

たとえば、stock_code 列の最大長を 5 に定義できますが、生成された ddl では、stock_code 列は varchar(10) です。この場合、エンティティの保存時に ConstraintViolationException をキャッチできます。

[エンティティが無効であることが判明した場合、ConstraintViolations のセットを公開する ConstraintViolationException によって、制約違反のリストが伝播されます。コミット時に違反が発生すると、この例外は RollbackException にラップされます。それ以外の場合は ConstraintViolationException が返されます (たとえば、 flush() を呼び出した場合]

うまくいけば、これはあなたの要件を満たしています。

あなたのエンティティクラスで

@Column(name = "stock_code", unique = true, nullable = false, length = 10)
@Size(max = 5)
public String getStockCode() {
    return this.stockCode;
}

public void setStockCode(String stockCode) {
    this.stockCode = stockCode;
}

あなたのdaoクラスで

try {
    session.beginTransaction();

    Stock stock = new Stock();

    stock.setStockCode("77777");
    stock.setStockName("PADINI");

    session.save(stock);
    session.getTransaction().commit();

} catch (ConstraintViolationException e) {
        session.getTransaction().rollback();
        System.out.println("Violate Constraint..");
    } catch (Exception e1) {
        session.getTransaction().rollback();
        System.out.println("Other Exception");
    } finally {
        session.close();
    }
于 2012-08-19T04:47:13.197 に答える
0

私の提案が「より良い」アプローチになるかどうかはわかりませんが、「他のアプローチ」を求めました:-)

私の最初のオプションは、次のようなものです。

public void setUsername(String username) {
    User user = user.clone();
    user.username = username;

    ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
    Validator validator = factory.getValidator();
    Set<ConstraintViolation<Car>> constraintViolations = validator.validateProperty(user, "username");

    if (constraintViolations.size() == 0) {
        this.username = username;
    } else {
        throw new IllegalArgumentException("Invalid username");
    }
}

もちろん、バリデーターへの静的参照を保持するヘルパー クラスを作成することでコードを最適化できるため、setUsername 呼び出しのたびにヘルパー クラスを作成する必要はありません。または、このロジック全体をヘルパーにカプセル化して、セッターにこれだけを渡すこともできます (バリデーターはユーザー名の値を変更するためにセッターを呼び出すべきではないため、このアプローチには注意してください)。

public void setUsername(String username) {
    MyValidatorHelper.validateOnSetter(this, username, "username");
    this.username = username;
}

この場合、MyValidatorHelper は例外をスローするため、2 行目は例外がスローされない場合にのみ実行されることに注意してください。

もう 1 つのオプションは、CDI インターセプターで遊ぶことです。私はテストしていませんが (前の例はテストしていません)、上記のロジックを CDI インターセプターにカプセル化し、@AroundInvoke でインターセプトできると思います。このようにして、セッター内からバリデーターヘルパーを呼び出すことを「忘れる」ことさえでき、CDI に呼び出してもらうことができます。これの欠点は、エンティティが CDI マネージド Bean である必要があり (とにかくそうである可能性があります)、すべてのセッターに対してデフォルトで有効にする必要があることです。これは良い考えかもしれませんし、そうでないかもしれません。

于 2012-08-19T08:33:24.880 に答える