这很容易通过 JPA 和 Hibernate 实现。
假设您正在使用以下book
数据库表:
映射实体
现在,您可以将两个实体:Book
和映射BookSummary
到此表。
首先,我们将创建一个BaseBook
由所有实体扩展的抽象类:
@MappedSuperclass
public abstract class BaseBook<T extends BaseBook> {
@Id
@GeneratedValue
private Long id;
@NaturalId
@Column(length = 15)
private String isbn;
@Column(length = 50)
private String title;
@Column(length = 50)
private String author;
public Long getId() {
return id;
}
public T setId(Long id) {
this.id = id;
return (T) this;
}
public String getIsbn() {
return isbn;
}
public T setIsbn(String isbn) {
this.isbn = isbn;
return (T) this;
}
public String getTitle() {
return title;
}
public T setTitle(String title) {
this.title = title;
return (T) this;
}
public String getAuthor() {
return author;
}
public T setAuthor(String author) {
this.author = author;
return (T) this;
}
}
现在,BookSummary
实体只是扩展了BaseBook
超类并且没有添加额外的实体属性。
@Entity(name = "BookSummary")
@Table(name = "book")
public class BookSummary extends BaseBook<BookSummary> {
}
另一方面,Book
实体扩展了BaseBook
超类并映射了properties
属性。
@Entity(name = "Book")
@Table(name = "book")
@TypeDef(
name = "jsonb",
typeClass = JsonBinaryType.class
)
@DynamicUpdate
public class Book extends BaseBook<Book> {
@Type(type = "jsonb")
@Column(columnDefinition = "jsonb")
private String properties;
public String getProperties() {
return properties;
}
public Book setProperties(String properties) {
this.properties = properties;
return this;
}
public ObjectNode getJsonProperties() {
return (ObjectNode) JacksonUtil
.toJsonNode(properties);
}
}
持久实体
这样,您可以持久化任一Book
实体:
entityManager.persist(
new Book()
.setIsbn("978-9730228236")
.setTitle("High-Performance Java Persistence")
.setAuthor("Vlad Mihalcea")
.setProperties(
"{" +
" \"publisher\": \"Amazon\"," +
" \"price\": 44.99," +
" \"publication_date\": \"2016-20-12\"," +
" \"dimensions\": \"8.5 x 1.1 x 11 inches\"," +
" \"weight\": \"2.5 pounds\"," +
" \"average_review\": \"4.7 out of 5 stars\"," +
" \"url\": \"https://amzn.com/973022823X\"" +
"}"
)
);
或BookSummary
:
entityManager.persist(
new BookSummary()
.setIsbn("978-1934356555")
.setTitle("SQL Antipatterns")
.setAuthor("Bill Karwin")
);
获取实体
您可以获取BookSummary
实体:
BookSummary bookSummary = entityManager
.unwrap(Session.class)
.bySimpleNaturalId(BookSummary.class)
.load("978-9730228236");
assertEquals(
"High-Performance Java Persistence",
bookSummary.getTitle()
);
或Book
实体,如果你想:
Book book = entityManager
.unwrap(Session.class)
.bySimpleNaturalId(Book.class)
.load("978-9730228236");
assertEquals(
"High-Performance Java Persistence, 2nd edition",
book.getTitle()
);
结论
因此将多个实体映射到同一个数据库表,不仅可以让我们更有效地获取数据,而且还可以加快脏检查过程,因为 Hibernate 必须检查的实体属性更少。
使用这种方法的唯一缺点是您必须确保您不会为同一个数据库表记录获取多个实体类型,否则在刷新持久性上下文时可能会导致不一致。