4

アプリケーションの起動時に、 Hibernate ( v 4.2.3 ) に 4 つの既存の DB テーブルを検証 ( = 検証) させようとしています。hbm2ddl.autoこれが私のテーブル作成SQLスクリプトです(これはH2 DBです):

-- Lookup/reference table, example records might be for ADVERB, NOUN,
-- VERB, etc.
CREATE TABLE word_types (
    word_type_id BIGINT AUTO_INCREMENT,
    word_type_label VARCHAR(100) NOT NULL,
    word_type_description VARCHAR(100) NOT NULL,
    word_type_tag VARCHAR(100) NOT NULL,
    CONSTRAINT uc_tag UNIQUE (word_type_tag)
);

-- A word in the English language. length is the number of chars in the
-- word, type ID is the word_types#word_type_id above (foreign key),
-- text is the actual word itself "quick", "fast", etc.
CREATE TABLE words (
    word_id BIGINT AUTO_INCREMENT,
    word_length INTEGER NOT NULL,
    word_type_id INTEGER NOT NULL,
    word_text VARCHAR(100) NOT NULL,
    word_definition VARCHAR(1000) NOT NULL,
    CONSTRAINT fk_word_types FOREIGN KEY (word_type_id) REFERENCES word_types(word_type_id),
    CONSTRAINT uc_text_type UNIQUE (word_text, word_type_id)
);

-- Crosswalk/junction table holding a many-to-many relationships between
-- pairs of words. Example: fast is a synonym of quick. So there would be
-- a words record for fast, and a words record for quick, and a record in
-- this table linking the 2 together.
CREATE TABLE synonyms (
    synonym_id BIGINT AUTO_INCREMENT,
    base_word_id INTEGER NOT NULL,
    has_synonym_id INTEGER NOT NULL,
    CONSTRAINT fk_word_1_base_id FOREIGN KEY (base_word_id) REFERENCES words(word_id),
    CONSTRAINT fk_word_synonym_id FOREIGN KEY (has_synonym_id) REFERENCES words(word_id),
    CONSTRAINT uc_syn_id_sets UNIQUE (base_word_id, has_synonym_id)
);

-- Same as above except this table relates words that are antonyms of
-- each other.
CREATE TABLE antonyms (
    antonym_id BIGINT AUTO_INCREMENT,
    base_word_id INTEGER NOT NULL,
    has_antonym_id INTEGER NOT NULL,
    CONSTRAINT fk_word_2_base_id FOREIGN KEY (base_word_id) REFERENCES words(word_id),
    CONSTRAINT fk_word_antonym_id FOREIGN KEY (has_antonym_id) REFERENCES words(word_id),
    CONSTRAINT uc_ant_id_sets UNIQUE (base_word_id, has_antonym_id)
);

したがって、4 つのテーブル: wordssynonyms& antonyms(さまざまな 間の多対多の関係を保持するwords) とルックアップ/参照テーブルword_types(ADVERB、NOUN など)。明確にするために、 "quick"wordsの値を持つレコードと"fast" のword_text別のwords/レコード/値がある場合、 "quick" の ID でword_textあるエントリがsynonymsテーブルに存在する可能性があり、"高速のID; quickにはfastという同義語があるためです。これらのテーブルに使用したいJavaモデルは次のとおりです。base_word_idhas_synonym_id

public class BaseModel {
    protected Long id;

    public Long getId() {
        return id;
    }

    public void setId(final Long id) {
        this.id = id;
    }
}

public class Word extends BaseModel {
    private String text;
    private Integer length;
    private WordType type;
    private String definition;
    private List<Word> synonyms;
    private List<Word> antonyms;

    // Getters, setters, ctors omitted for brevity...
}

public class BaseLookup extends BaseModel {
    private String label;
    private String description;
    private String tag;

    // Getters, setters, ctors omitted for brevity...
}

public class WordType extends BaseLookup {
    public WordType(String label, String description, String tag) {
        super(label, description, tag);
    }
}

そのBaseModelため、各モデルに ID を提供します。BaseLookupすべてのルックアップ テーブルに少なくとも 3 つのフィールド/列があります。Word非常に単純明快でWordType、親にフィールドを追加しないルックアップ ラッパーです。しかし、いつの日か、提供されるラベル/説明/タグ フィールドを超えてフィールドを追加するBaseLookupサブクラスを持つことが非常に考えられるかもしれませBaseLookup

そのため、Java とデータ モデルの両方を使用するように Hibernate が正しく構成されるように、各クラスに追加する必要がある注釈を見つけようとしていますが、いくつかのレンガの壁にぶつかっています。これが私が思いついた最高のものです:

// This class doesn't translate into a table; it's just a base class that provides
// an ID for all other entities, and perhaps (down the road) other common fields as
// well.
public class BaseModel {
    @Id @GeneratedValue(strategy=GenerationType.AUTO)
    protected Long id;

    public Long getId() {
        return id;
    }

    public void setId(final Long id) {
        this.id = id;
    }
}

@Entity
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
@Table(name="words")
public class Word extends BaseModel {
    // How do I force Word.getId() to be "words_id"?

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

    @Column(name="word_length")
    private Integer length;

    // But how do I make this the ID of a word_types record?
    @Column(name="word_type_id")
    private WordType type;

    @Column(name="word_definition")
    private String definition;

    // The words table doesn't have any synonyms or antonyms.
    // Rather there is a many-to-many relationship between
    // a word and its synonyms and its antonyms...
    @Column(name="???")
    private List<Word> synonyms;

    @Column(name="???")
    private List<Word> antonyms;

    // Getters, setters, ctors omitted for brevity...
}

// Not sure what to annotate this table with, because there is not
// base_lookup table or anything like that...
public class BaseLookup extends BaseModel {
    private String label;
    private String description;
    private String tag;

    // Getters, setters, ctors omitted for brevity...
}

// Furthermore, here, in the case of WordType, I'd like to force the parent
// fields to be "word_type_label", "word_type_description", and "word_type_tag";
// however, other BaseLookup subclasses should be able to force those same fields
// to map/bind to other tables with other field names.
//
// For example, I might some day want a Color POJO relating to a colors table with
// the following fields: color_label, color_description and color_tag, etc.
public class WordType extends BaseLookup {
    // How do I force WordType.getId() to be word_type_id?

    public WordType(String label, String description, String tag) {
        super(label, description, tag);
    }
}

Hibernate が Java とデータ モデルの両方に対応できるように、戦いに疲れた Hibernate のベテランが POJO クラス/フィールドに正しく注釈を付けるのを手伝ってくれますか? 具体的には、次のソリューションが必要です。

  1. 他のすべてのエンティティの IDを作成する方法ですが、エンティティごとに一意の列名 ( 、color_id` など)BaseModel#idを持つ一意の列として表示されます。word_idword_type_id
  2. Word#typeHibernate がword_type_id外部キーであることを認識できるように、フィールドに注釈を付ける方法。Wordまた、 DB から POJO インスタンスを取得するときに、そのWordTypeタイプが既に取り込まれているようにカスケードする必要があります。
  3. 注釈を付けWord#synonymsWord#antonyms、Hibernate がそれらの関係を (同じ名前の) crosswalk テーブルに保存する方法。
  4. Hibernate が次のフィールドで呼び出されるテーブルを探すことを認識するように注釈を付ける方法WordTypeなど: 、および。しかし、他のサブクラスも持つことができるような方法でそれらに注釈を付けてください.BaseLookupword_typesword_type_labelword_type_descriptionword_type_tagBaseLookupColorcolorscolor_labelcolor_descriptioncolor_tag

前もって感謝します!

4

1 に答える 1

1

DBにテーブルがあり、DBテーブルを持たずに継承階層のJPAアノテーションを保存したいだけの場合@Entityは、(継承階層の)開始点から使用するだけでよいと思います (あなたの場合はand )。@MappedSuperClassBaseModelBaseLookup

@AttributeOverrideマッピング情報をオーバーライドするためのアノテーションもユースケースで役立ちます。

また、リレーションシップの一部であるマッピング情報を設定するには、 、、またはアノテーションのいずれか@JoinColumnと組み合わせて使用​​します。@ManyToMany@ManyToOne@OneToMany@OneToOne

4 つの質問すべてに対する回答については、私の回答の下部を参照してください。

// This class doesn't translate into a table; it's just a base class that provides
// an ID for all other entities, and perhaps (down the road) other common fields as
// well.
@MappedSuperClass
public class BaseModel {
    @Id @GeneratedValue(strategy=GenerationType.AUTO)
    protected Long id;

    public Long getId() {
        return id;
    }

    public void setId(final Long id) {
        this.id = id;
    }
}

@Entity
@AttributeOverrides({
        @AttributeOverride(name="id", column=@Column(name="word_id"))
})
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
@Table(name="words")
public class Word extends BaseModel {
    // How do I force Word.getId() to be "words_id"?

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

    @Column(name="word_length")
    private Integer length;

    // But how do I make this the ID of a word_types record?
    //@Column(name="")
    @ManyToOne
    @JoinColumn(name="word_type_id", referencedColumnName="word_type_id")
    private WordType type;

    @Column(name="word_definition")
    private String definition;

    // The words table doesn't have any synonyms or antonyms.
    // Rather there is a many-to-many relationship between
    // a word and its synonyms and its antonyms...
    @ManyToMany()
    //use the below annotation if you want to set the names of the columns
    //    @JoinTable(joinColumns = @JoinColumn(name="word_id")},//column in this entity
    //          inverseJoinColumns = {@JoinColumn(name="synonym_id")})//column in the table of the set.
    private List<Word> synonyms;

    //@Column(name="???")
    @ManyToMany()
    //use the below annotation if you want to set the names of the columns
    //    @JoinTable(joinColumns = @JoinColumn(name="word_id")},//column in this entity
    //          inverseJoinColumns = {@JoinColumn(name="antonym_id")})//column in the table of the set.
    private List<Word> antonyms;

    // Getters, setters, ctors omitted for brevity...
}

// Not sure what to annotate this table with, because there is not
// base_lookup table or anything like that...
@MappedSuperClass
public class BaseLookup extends BaseModel {
    private String label;
    private String description;
    private String tag;

    // Getters, setters, ctors omitted for brevity...
}

// Furthermore, here, in the case of WordType, I'd like to force the parent
// fields to be "word_type_label", "word_type_description", and "word_type_tag";
// however, other BaseLookup subclasses should be able to force those same fields
// to map/bind to other tables with other field names.
//
// For example, I might some day want a Color POJO relating to a colors table with
// the following fields: color_label, color_description and color_tag, etc.
@Entity
    // How do I force WordType.getId() to be word_type_id?
    // this is how:
@AttributeOverrides({
    @AttributeOverride(name="id", column=@Column(name="word_type_id")),
    @AttributeOverride(name="label", column=@Column(name="word_type_label")),
    @AttributeOverride(name="description", column=@Column(name="word_type_description")),
    @AttributeOverride(name="tag", column=@Column(name="word_type_tag"))
})
public class WordType extends BaseLookup {


    public WordType(String label, String description, String tag) {
        super(label, description, tag);
    }
}

そして今、あなたの質問に答えるために:

1. BaseModel#id を他のすべてのエンティティの ID にする方法。ただし、エンティティごとに一意の列名 (word_id、word_type_id、color_id` など) を持つ一意の列として表示します。

@AttributeOverridesで注釈が付けられたクラスを拡張するクラスで使用します@MappedSuperClass(これらはエンティティではないため、DB テーブルにマップされません)。

2.Hibernate が word_type_id 外部キーであることを認識できるように、Word#type フィールドに注釈を付ける方法。また、DB から Word POJO インスタンスを取得するときに、その WordType 型が既に取り込まれているようにカスケードする必要があります。

@ManyToManyのような注釈を使用します。WordTypeの読み込みは自動で行われます。@ManyToMany逆の効果を得るために、 のような注釈で fetch=FetchType.LAZY パラメータを検討することもできます。

3. Word#synonyms と Word#antonyms に注釈を付けて、Hibernate が (同じ名前の) crosswalk テーブルにそれらの関係を格納するようにする方法。

(必要に応じて)@ManyToManyと組み合わせて使用​​する@JoinTable

4. Hibernate が次のフィールドを持つ word_types と呼ばれるテーブルを探すことを認識できるように、WordType と BaseLookup に注釈を付ける方法: word_type_label、word_type_description、および word_type_tag。ただし、color_label、color_description、color_tag を含む色テーブルに関連する可能性のある Color など、他の BaseLookup サブクラスも持つことができるように、それらに注釈を付けます。

1と同じ。

PS: JPAでは、(エンティティに)誰もいない場合に備えて、すべてのエンティティにデフォルトのコンストラクターが必要ですWordType。さらに、一部のクラスを抽象化し、テーブル名に単数形を使用することに関連するコメントからのアドバイスを検討することもできます。一部の列の一意性に関する質問に明示的に対処していませんが、その方法の詳細については、この回答を参照してください。

于 2013-10-29T15:42:51.803 に答える