I am trying to get Hibernate (v 4.2.3) to validate (hbm2ddl.auto
= validate) my 4 existing DB tables when the application starts up. Here are my table create SQL scripts (this is an 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)
);
Hence, 4 tables: words
, synonyms
& antonyms
(which hold many-to-many relationships between different words
) and a lookup/reference table word_types
(such as ADVERB, NOUN, etc.). To clarify, if there is a words
record with a word_text
value of "quick", and another words
/word_text
record/value of "fast", then there may be an entry in the synonyms
table where the base_word_id
is "quick"'s ID, and has_synonym_id
might be "fast"'s ID; because quick has a synonym called fast. Here is the Java model I want to use for these tables:
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);
}
}
So BaseModel
provides each model with an ID. BaseLookup
provides three fields/columns that all lookup tables will have, at a minimum. Word
is pretty straight-forward, and WordType
is a lookup wrapper that doesn't add any additional fields over its parent. However it may be very conceivable to one day have a BaseLookup
subclass that does add fields beyond the label/description/tag fields that BaseLookup
provides.
So I'm trying to figure out which annotations I need to add to each of my classes so that Hibernate is configured correctly to use both my Java and data models, and I'm running into some brick walls. Here is the best I've been able to come up with:
// 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);
}
}
Can some battle-weary Hibernate veteran help me correctly annotate my POJO classes/fields so that Hibernate will accommodate both my Java and data models? Specifically, I need solutions for:
- How to make
BaseModel#id
the ID for all other entities, but to appear as a unique column with a unique column name for each entity (word_id
,word_type_id
, color_id`, etc.). - How to annotate the
Word#type
field so that Hibernate knows it is theword_type_id
foreign key. Also, I need cascading to work in such a way that when I obtain aWord
POJO instance from the DB, it is already populated with itsWordType
type. - How to annotate
Word#synonyms
andWord#antonyms
so that Hibernate stores their relationships in the crosswalk tables (of the same names). - How to annotate
WordType
andBaseLookup
such that Hibernate knows to look for a table calledword_types
with the following fields:word_type_label
,word_type_description
andword_type_tag
. But, annotate them in such a way that I could also have otherBaseLookup
subclasses, likeColor
that might relate to acolors
table withcolor_label
,color_description
andcolor_tag
.
Thanks in advance!