3

inputPeriodという名前のカスタムJSF入力コンポーネントがあります。これは、日付期間を入力するように設計されています。各期間には、開始日と終了日があります。コンポーネントの機能は、JSON文字列を生成してコンポーネントに送信するJavascriptで実現されます。次に、入力コンポーネントは、JSON期間をPeriodオブジェクトのリストに変換し、それらを管理対象Beanに設定するデフォルトのコンバーターを使用します。これはすべて完璧に機能します。

私が抱えている問題の原因は、EJBエンティティで同じコンポーネントを使用したいということです。BannerPeriodエンティティと1対多の関係にあるBannerエンティティがあります。BannerPeriodエンティティの各インスタンスは、入力コンポーネントで使用している既存のPeriodオブジェクトとまったく同じように、開始日と終了日を取得します。私はこれのために新しいコンバーターを実装しました:

@ManagedBean
@RequestScoped
public class BannerPeriodConverter implements Converter {

    @Override
    public Object getAsObject(FacesContext fc, UIComponent uic, String str) {
        if (str != null) {
            Date from = null, to = null;
            try {
                JSONObject period = new JSONObject(str);
                if (period.has("from")) {
                    from = new Date(period.getLong("from"));
                }
                if (period.has("to")) {
                    to = new Date(period.getLong("to"));
                }
            } catch (JSONException ex) {
                throw new ConverterException(ex);
            }
            BannerPeriod bp = new BannerPeriod();
            bp.setBegins(from);
            bp.setEnds(to);
            return bp;
        }
        return null;
    }

    @Override
    public String getAsString(FacesContext fc, UIComponent uic, Object o) {
        if (o != null && o instanceof BannerPeriod) {
            BannerPeriod bp = (BannerPeriod) o;
            JSONObject period = new JSONObject();
            try {
                period.put("from", bp.getBegins() != null ? bp.getBegins().getTime() : (Object) null);
                period.put("to", bp.getEnds() != null ? bp.getEnds().getTime() : (Object) null);
            } catch (JSONException ex) {
                throw new ConverterException(ex);
            }
            return period.toString();
        }
        return "";
    }
}

コンバーターはコンポーネントで正常に動作します。私が抱えている問題は、既存のバナー期間でバナーを編集すると、エンティティが主キーを失うことです。したがって、フォームを送信すると、既存の期間を更新する代わりに、重複する例外が発生するか、既存の期間が再度作成されて、データベースに実際の重複が作成されます。

だから私の質問は、これを避けるために何ができるかということです。私の推測では、入力コンポーネントは何らかの形で既存のエンティティの主キーを保持する必要がありますが、どうすればそのようなものを作成するのが最善でしょうか?現時点では、入力コンポーネントはエンティティとEJBプロジェクトから完全に切り離されています。入力コンポーネントは独自のJSFプロジェクトにありますが、上記のコンバーターはEJBプロジェクトにあります。デフォルトでは、入力コンポーネントは、主キーをまったく持たないプレーンなPeriodオブジェクトで機能します。それはそうし続けるべきです。

それとも、これは他の方法で解決する必要がありますか?

4

1 に答える 1

1

あなたの場合、JPAを介してDBから直接インスタンスを取得するのgetAsObject()ではなく、完全にアンマネージドのインスタンスを作成しています。BannerPeriod

BannerPeriod bp = new BannerPeriod();
bp.setBegins(from);
bp.setEnds(to);
return bp;

もちろん、それを永続化すると、JPAによって管理されていないため、DBに新しいエントリが作成されます。

基本的には、代わりにJPAを介してDBからインスタンスを取得する必要があります。

@EJB
private BannerPeriodService service;

public Object getAsObject(FacesContext context, UIComponent component, String value) {
    // ...

    return service.find(from, to);
}

ここで、はBannerPeriodService#find()を介して目的のインスタンスを取得しますEntityManager

しかし、このアプローチはかなり不器用です。DBのエンティティの場合、標準的なアプローチは、自動生成された主キーなど、技術的/自然な識別子を使用することです。

例(null /インスタンスのチェックなどは省略):

@EJB
private BannerPeriodService service;

public Object getAsString(FacesContext context, UIComponent component, Object value) {
    Long id = ((BannerPeriod) value).getId();
    return id.toString();
}

public Object getAsObject(FacesContext context, UIComponent component, String value) {
    Long id = Long.valueOf(value);
    return service.find(id);
}

JSON形式を台無しにする必要はありません。不明確な理由で実際にJSON形式でそれらが必要な場合は、これにJSFコンバーターを使用することで間違った方向に進んでいます。

コンバーターでDBをヒットするのは、比較的コストのかかる作業であることを理解しています。その場合、OmniFacesSelectItemsConverterはあなたが探しているものかもしれません。

于 2013-03-13T14:30:12.307 に答える