首先,我已阅读Hibernate - One table with multiple entities?。
但是,我想将两个实体映射到同一个表,但我希望它们都是实体,我可以从中选择。我的意思是:
所以它是实体之间的1:1关系,但仍然是数据库中的1个表。
如果我在上面的链接中使用建议的解决方案(组件关键字),我不能直接查询地址(我可以通过Person实体访问它)。我希望能够做到
session.createCriteria(Adres.class)
我该怎么做?
更新: 我在地址映射中尝试了实体之间的一对一关联:
<one-to-one name="Person " class="model_mapowanie_xml.Person "/>
和in person mapping:
<one-to-one name="Address" class="model_mapowanie_xml.Address "/>
两个类都有字段引用另一个。选择记录可以正常工作。但是,如何使用两个实体在一个事务中添加记录? (Id是db生成的)
Address ad = new Address();
ad.setProperty("Sydney");
Person p = new Person();
p.setProperty("John");
p.setAddress(ad);
session.save(p);
并且只保存Person部分,地址属性保持为空。
答案 0 :(得分:1)
您应该可以使用@Table
注释来执行此操作。这些entites将被视为不同的entites,但将被映射到同一个表。
@Entity
@Table(name="PERSON_TABLE")
class Person {}
@Entity
@Table(name"PERSON_TABLE")
class Address {}
编辑:
如果要在一个事务中保存两个实体,则必须使用Session
显式保存它们,或者设置cascade
属性以对关系进行级联操作。我猜你想在Person上做一些事情时在地址上级联操作。如果您使用注释,请参阅CascadeType。
在你的hbm中看起来像
<one-to-one name="Person" class="model_mapowanie_xml.Person" cascade="all"/>
答案 1 :(得分:1)
正如我在诠释this article中所解释的那样,使用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必须检查较少的实体属性,因此它还加快了脏检查过程。
使用这种方法的唯一缺点是,必须确保对于同一数据库表记录,不要获取多个实体类型,否则,刷新持久化上下文时可能会导致不一致。