我正在尝试让 Hibernate (v 4.2.3) 在应用程序启动时验证(hbm2ddl.auto
= 验证)我的 4 个现有数据库表。这是我的表创建 SQL 脚本(这是一个 H2 数据库):
-- 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 个表:words
, synonyms
& antonyms
(在不同的 words
之间保持多对多关系)和查找/引用表 word_types
(如副词、名词等)。澄清一下,如果有 words
用 word_text
记录“quick”的值(value),和另一个words
/word_text
“fast”的记录/值,则synonyms
中可能有一个条目base_word_id
所在的表是“quick”的 ID,has_synonym_id
可能是“快”的 ID;因为 quick 有一个同义词叫做 fast。这是我想用于这些表的 Java 模型:
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
至少提供所有查找表都将具有的三个字段/列。 Word
非常简单,WordType
是一个查找包装器,不会在其父项上添加任何其他字段。但是很可能有一天会有一个BaseLookup
确实的子类在标签/描述/标签字段之外添加字段 BaseLookup
提供。
所以我试图弄清楚我需要将哪些注释添加到我的每个类中,以便正确配置 Hibernate 以使用我的 Java 和数据模型,但我遇到了一些问题。这是我能想到的最好的:
// 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 老手可以帮助我正确地注释我的 POJO 类/字段,以便 Hibernate 能够适应我的 Java 和数据模型吗?具体来说,我需要针对以下方面的解决方案:
- 如何制作
BaseModel#id
所有其他实体的 ID,但显示为每个实体具有唯一列名称的唯一列(word_id
、word_type_id
、color_id` 等)。 - 如何注释
Word#type
字段以便 Hibernate 知道它是word_type_id
外键。另外,我需要级联才能在获得Word
时以这种方式工作。来自数据库的 POJO 实例,它已经填充了它的WordType
类型。 - 如何注释
Word#synonyms
和Word#antonyms
以便 Hibernate 将它们的关系存储在人行横道表(同名)中。 - 如何注释
WordType
和BaseLookup
这样 Hibernate 就知道要查找名为word_types
的表具有以下字段:word_type_label
,word_type_description
和word_type_tag
. 但是,以我也可以有其他BaseLookup
的方式注释它们子类,如Color
这可能与colors
有关表color_label
,color_description
和color_tag
.
提前致谢!
最佳答案
我认为当你在数据库中有表时,你只需要从起点(在你的继承层次结构中)使用 @Entity
,如果你只是想使用 @MappedSuperClass
存储继承层次结构的 JPA 注释,而无需数据库表(在您的情况下为 BaseModel
和 BaseLookup
)。
为了覆盖映射信息,@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.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.).
在使用 @MappedSuperClass
注释的类的扩展类上使用 @AttributeOverrides
(它们不是实体,因此不会映射到数据库表)。
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.
使用类似@ManyToMany
的注解。 WordType 的加载是自动进行的。您可能会考虑在类似 @ManyToMany
的注释中使用 fetch=FetchType.LAZY 参数来达到相反的效果。
3.How to annotate Word#synonyms and Word#antonyms so that Hibernate stores their relationships in the crosswalk tables (of the same names).
将@ManyToMany
与@JoinTable
结合使用(如果需要)
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.
同1.
PS:在 JPA 中,您必须在每个实体中都有默认构造函数,如果没有(在您的 WordType
实体中) ).此外,您可能会考虑与使某些类抽象化并在表名中使用单数相关的评论中的建议。尽管您没有明确解决某些列的唯一性问题:请参阅 this response有关如何制作的详细信息。
关于java - 如何注释 Hibernate 实体以同时支持 Java 和数据模型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19617525/