1

POST には多くの TAG があり、TAG には多くの POST がある典型的な例があります。典型的な を使用する代わりに、@ManyToManyTAGPOST と呼ばれる中間のドメイン オブジェクトを使用します。これにより、投稿が特定のタグでタグ付けされたときなど、そこに有用なデータを含めることもできます。各 POST、および TAG resp、 TAGPOSTと@OneToMany関係があります。

特定の要件として、投稿に同じタグを 2 回含めることはできないため、TAGPOST.post と TAGPOST.tag のペアは常に一意である必要があります。通常は、TAGPOST オブジェクトの格納を担当する複合主キー ペアをテーブルに作成することでこれを行います。

私の知る限り、この一意の制約を表現する方法はありません。をマークjpa.ddl=updateしました。つまり、アプリケーションを新しい環境に移動するたびに、DB でこれを手動で修正する必要があります。これは非常に不便で、特に単体テストの場合はエラーが発生しやすくなります。これは、反復ごとに多かれ少なかれデータベースが作成され、削除されるためです。

で手動でチェックを行うか、チェックを@PrePersistビジネスレイヤーに移動して、PostService を作成することさえ考えていました。

私は何をしますか?Play がデフォルトで持っているものを見逃していますか? @ManyToOneTAGPOST クラスのプロパティの一意性を表現するための巧妙な注釈はありますか?

参考までに: 私は Play 1.2.5 を使用しています

編集: TAGPOST クラスは次のようになります。

@Entity
public class TagPost extends Model {

    @ManyToOne
    public Tag tag;

    @ManyToOne
    public Post post;

    public Date dateAdded;

    ...
}
4

1 に答える 1

0

Checkdbの一意性のカスタムを作成しました。多分あなたはそれをカスタマイズする必要があります。

DBUnique.java

package models.check;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import net.sf.oval.configuration.annotation.Constraint;
import play.db.jpa.GenericModel;

@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD, ElementType.PARAMETER })
@Constraint(checkWith = DbUniqueCheck.class)
public @interface DBUnique {
    String message() default DbUniqueCheck.mes;

    Class<? extends GenericModel> modelClass();

    String field() default ""; // field name will be used
}

DbUniqueCheck.java

package models.check;


import net.sf.oval.Validator;
import net.sf.oval.configuration.annotation.AbstractAnnotationCheck;
import net.sf.oval.context.FieldContext;
import net.sf.oval.context.OValContext;

import org.apache.commons.lang.StringUtils;

import play.db.jpa.GenericModel.JPAQuery;

@SuppressWarnings("serial")
public class DbUniqueCheck extends AbstractAnnotationCheck<DBUnique> {

final static String mes = "validation.dbunique";
DBUnique dbUnique;

@Override
public void configure(DBUnique dBUnique) {
    this.dbUnique = dBUnique;
    setMessage(dBUnique.message());
}

public boolean isSatisfied(Object validatedObject, Object value, OValContext context, Validator validator) {
    try {
        String field = dbUnique.field();
        if (field == null || field.isEmpty()) {
            field = ((FieldContext) context).getField().getName();
        }
        JPAQuery q = (JPAQuery) dbUnique.modelClass().getMethod("find", String.class, Object[].class)
                .invoke(null, "by" + StringUtils.capitalize(field), new Object[] { value });
        return q.first() == null;
    } catch (Exception e) {
        e.printStackTrace();
    }
    return false;
}

}

使用法:要点へのリンク

field指定されたclassインスタンスがdbで一意であることを確認するだけです。多分あなたはこれらのようなものを作るべきです。

于 2013-03-23T08:37:00.727 に答える