2

Java EE 6プロジェクトでローカライズされた動的(ユーザーが作成、dbに保存)データの必要性を解決するために、任意の言語の任意の文字列を格納できる一般的なローカライズされた文字列テーブルを作成しました。これは、名前だけを含む15個までの余分なテーブルを作成する必要がないようにするためです。私が知りたいのは2つのことです。

1)これは良い考えですか、悪い考えですか。その理由は何ですか。2)短所にリストされている問題のクリーンな解決策を知っていますか?

私の経験:

長所:必要なテーブルは1つだけで、jpaとdbの両方で簡単に構成できる一般的なソリューションです。重複したコードは存在しません。

短所:私が見つけた大きな問題は、muiltilingual_stringテーブルがそれを使用しているオブジェクトを認識しているため、カスケード削除がSQLから機能しないことです(ただし、orphanRemovalを使用するJPAでは機能します)。これにより、JPAの外部から作業した場合に、「デッド」文字列がデータベースに残る可能性が生じます。

エンティティ:(AbstractEntityは、@ idと@versionを含むマップされたスーパークラスです)

@Entity
@Table(schema = "COMPETENCE", name = "multilingual_string")
public class MultilingualString extends AbstractEntity{

    @ElementCollection(fetch=FetchType.EAGER)
    @MapKey(name = "language")
    @CollectionTable(schema = "COMPETENCE", name = "multilingual_string_map",
                     joinColumns = @JoinColumn(name = "string_id"))
    private Map<Language, LocalizedString> map = new HashMap<Language, LocalizedString>();

    public MultilingualString() {}

    public MultilingualString(Language lang, String text) {
        addText(lang, text);
    }

    public void addText(Language lang, String text) {
        map.put(lang, new LocalizedString(lang, text));
    }

    public String getText(Language lang) {
        if (map.containsKey(lang)) {
            return map.get(lang).getText();
        }
        return null;
    }

    public LocalizedString getLocalizedString(Language lang){
        if(map.get(lang) == null)
            map.put(lang, new LocalizedString(lang, null));
        return map.get(lang);
    }

    @Override
    public MultilingualString clone(){
        MultilingualString ms = new MultilingualString();
        for(LocalizedString s : map.values())
            ms.addText(s.getLanguage(), s.getText());
        return ms;
    }

    @Override
    public String toString() {
        return getId() == null ? "null " + this.getClass().getName() : getId().toString();
    }
}

@Embeddable
public class LocalizedString {

    @JoinColumn(name="lang_id")
    private Language language;

    @Column(name="text")
    private String text;

    public LocalizedString() {
    }

    public LocalizedString(Language language, String text) {
        this.language = language;
        this.text = text;
    }

    public Language getLanguage() {
        return language;
    }

    public void setLanguage(Language language) {
        this.language = language;
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

}

クラスは、他のエンティティで次のように使用されます。

@OneToOne(cascade=CascadeType.ALL, orphanRemoval=true)
@JoinColumn(name = "summary_stringid")
private MultilingualString summary;

テーブル:

MULTILINGUAL_STRING (
    id bigint primary key
);

MULTILINGUAL_STRING_MAP (
    string_id bigint FOREIGN KEY REFERENCES MULTILINGUAL_STRING(id), 
    lang_id bigint FOREIGN KEY REFERENCES LANG(id),
    text varchar(2000 char),
    PRIMARY KEY(string_id, lang_id)
);

次のように使用されます:

COMPETENCE (
    id bigint PRIMARY KEY,
    name_id bigint FOREIGN KEY REFERENCES MULTILINGUAL_STRING(id)
);
4

2 に答える 2

1

このようなアプローチ理にかなっており、新しいものではありません。ここでさまざまな JPA プロバイダーに対して公開、議論、テストされました: http://hwellmann.blogspot.com/2010/07/jpa-20-mapping-map.html (そこからコードを取得したと思います)

于 2012-03-30T19:18:42.347 に答える
1

私が見る 1 つの質問は、これが ResourceBundle のカスケードのように機能しないように見えるということです。

ResourceBundle では、ロケールが ES_es の場合、最初に ES_es でローカライズされたバージョンを探します。見つからない場合は ES で試し、そうでない場合はデフォルトの文字列を探します (失敗した場合は # が表示されます)。 STRING_ID 文字列)。.EN ディクショナリ、英国固有の表現用の .EN_uk、および米国固有の表現用の .EN_us を持つことができ、EN_uk と EN_us には必要なキーのみを配置します。

システムでは、これらのオプションをすべて許可せずに現在のロケールを参照するだけなので、ロケールごとにすべての値を再定義する必要があります。したがって、上記の例では、EN_uk と EN_us の両方のキーごとに値を設定する必要があります。

于 2011-05-11T12:29:18.857 に答える