OneToMany和ManyToOne是更为常见的例子。如果A和B的关系是OneToMany,则B和A的关系就是ManyToOne。
小例子
我们继续前面书的例子,增加书评表。一本书可以有多条书评,一条书评对应一本书。
CREATE TABLE Book (
Id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
BookName VARCHAR(50) NOT NULL
) ENGINE = InnoDB;
CREATE TABLE Book_Comment (
Id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
Commentator VARCHAR(32) NOT NULL,
Book_Id BIGINT UNSIGNED NOT NULL,
Comment VARCHAR(1024) NOT NULL,
CONSTRAINT `BOOK_BOOK_COMMENT` FOREIGN KEY (`Book_Id`) REFERENCES Book (`Id`) ON DELETE CASCADE
) ENGINE = InnoDB;
单向的ManyToOne
Book和普通的Entity没有区别,BookComment如下
@Entity(name = "Book_Comment")
public class BookComment {
private long id;
private String commentator;
private Book book;
private String comment;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
public long getId() { ... }
/* 【1】标记这是一个ManyToOne的关系,且对方必须存在(optional = false) */
@ManyToOne(optional = false)
/* 【2】@JoinColumn是用来标记关联两个表的列。*/
@JoinColumn(name = "Book_Id")
public Book getBook() { ...}
......
}
单向的OneToMany
作为Many的BookComment和普通的Entity无异,Book如下:
@Entity
public class Book {
private long id;
private String bookName;
private Set<BookComment> comments = new HashSet<>();
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
public long getId() { ... }
/* 【1】标记OneToMany,要求如果删除了相关的BookComment信息,则对方表格的信息也删除(orphanRemoval = true)
* 【2】只要是单向关系,都应该提供@JoinColumn信息:OneToMany给的对方表格关联本表格主键的列,也即对方表格的外键。*/
@OneToMany(fetch = FetchType.LAZY,cascade = CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name = "Book_Id")
public Set<BookComment> getComments() { ... }
......
}
双向OneToMany和ManyToOne
ManyToOne和单向的ManyToOne没有什么区别
@Entity(name = "Book_Comment")
public class BookComment {
... ...
private Book book;
/* 【1】标记这是一个ManyToOne的关系,且对方必须存在(optional = false) */
/* 【2】@JoinColumn是用来标记关联两个表的列。*/
@ManyToOne(optional = false)
@JoinColumn(name = "Book_Id")
public Book getBook() { ...}
......
}
OneToMany中通过mappedby表示双向映射,而不是两个单向。
@Entity
public class Book {
... ...
private Set<BookComment> comments = new HashSet<>();
/* 【1】标记OneToMany,给出了关系的另一头(BookComment)中哪个属性和本entity对应
* 【2】已经有了mappedBy表明关联关系,无需@JoinColumn */
@OneToMany(fetch = FetchType.LAZY,cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "book")
public Set<BookComment> getComments() { ... }
......
}
带排序的List
小例子我们使用了Set,还可以使用List,Map等集合方式,可以指定特定的排序。
@Entity
public class Book {
... ...
private List<BookComment> comments = new ArrayList<>();
@OneToMany(fetch = FetchType.LAZY,cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "book")
/* List里面的元素将按BookComment的属性commentator进行排序。 */
@OrderBy("commentator")
public Set<BookComment> getComments() { ... }
......
}
使用Map,指定Key
@Entity
public class Book {
... ...
private Map<String,BookComment> comments = new HashMap<>();
@OneToMany(fetch = FetchType.LAZY,cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "book")
/* 以BookComment的属性commentator作为Key。
* 由于Map的特点,如果一个评论员有两条评论,在map中只会有一条。Map不适用于本小场景,只是说明一种方式。 */
@MapKey(name="commentator")
public Set<BookComment> getComments() { ... }
......
}