I think you simply need to use @Entity
from the starting point (in your inheritance hierarchy) when you have tables in DB and @MappedSuperClass
if you just want to store JPA annotations for the inheritance hierarchy, without having DB tables (in your case for BaseModel
and BaseLookup
).
Also useful in your use case is the @AttributeOverride
annotation in order to override the mapping information.
Besides, in order to set some mapping information that are part of a relationship, you use @JoinColumn
in combination with one of the @ManyToMany
, @ManyToOne
, @OneToMany
or @OneToOne
annotations.
For answers to every of your 4 questions, see the bottom part of my response.
// 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);
}
}
And now to answer your questions:
1.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.).
Use @AttributeOverrides
on classes that extend classes annotated with @MappedSuperClass
(they are not entities, thus not mapped to DB tables).
2.How to annotate the Word#type field so that Hibernate knows it is the word_type_id foreign key. Also, I need cascading to work in such a way that when I obtain a Word POJO instance from the DB, it is already populated with its WordType type.
Use @ManyToMany
-like annotations. Loading of WordType is made automatically. You might consider the fetch=FetchType.LAZY parameters in the @ManyToMany
-like annotations for the opposite effect.
3.How to annotate Word#synonyms and Word#antonyms so that Hibernate stores their relationships in the crosswalk tables (of the same names).
Use @ManyToMany
in combination with @JoinTable
(if needed)
4.How to annotate WordType and BaseLookup such that Hibernate knows to look for a table called word_types with the following fields: word_type_label, word_type_description and word_type_tag. But, annotate them in such a way that I could also have other BaseLookup subclasses, like Color that might relate to a colors table with color_label, color_description and color_tag.
The same as 1.
PS: In JPA you MUST have the default constructor in every entity, in the case there is no one (in your WordType
entity). Besides you might consider the advice from comments related to making abstract some classes and using the singular in your table names. Although you didn't explicitly addressed the question with Uniqueness of some columns: see this response for details how to make that.