Hibernate - 一张表多个实体

Day*_*Tex 6 sql hibernate

首先,我读过Hibernate - One table with multiple entity? .

但是,我想将两个实体映射到同一个表,但我希望它们都是实体,我可以从中进行选择。我的意思是:

  • 一张表:Person(id、name、dateOfBirth、城市、街道、邮政编码)。
  • 两个实体:人(id、name、dateOfBirth)、地址(id、城市、街道、邮政编码)。

所以它是实体之间的 1:1 关系,但在 DB 中仍然是 1 个表。

如果我使用上述链接中建议的解决方案(组件关键字)来执行此操作,则无法直接查询地址(我可以通过 Person 实体访问它)。我希望能够做到

session.createCriteria(Adres.class)
Run Code Online (Sandbox Code Playgroud)

我怎么做?

更新:我在地址映射中尝试了实体之间的一对一关联:

<one-to-one name="Person " class="model_mapowanie_xml.Person "/>
Run Code Online (Sandbox Code Playgroud)

和个人映射:

<one-to-one name="Address" class="model_mapowanie_xml.Address "/>
Run Code Online (Sandbox Code Playgroud)

两个类都有引用另一个类的字段。选择记录可以很好地解决这个问题。但是,如何在一个交易中使用两个实体添加一条记录?(Id 是数据库生成的)

Address ad = new Address();
ad.setProperty("Sydney");
Person p = new Person();
p.setProperty("John");
p.setAddress(ad);
session.save(p);
Run Code Online (Sandbox Code Playgroud)

并且只保存了 Person 部分,address 属性保持为空。

Mar*_*rek 5

您应该能够使用@Table注释来完成此操作。这些实体将被视为不同的实体,但将映射到同一个表上。

@Entity
@Table(name="PERSON_TABLE")
class Person {}


@Entity
@Table(name"PERSON_TABLE")
class Address {}
Run Code Online (Sandbox Code Playgroud)

编辑:

如果您想将两个实体保存在一个事务中,您必须使用显式保存它们Session或将cascade属性设置为关系上的级联操作。我猜想当您对 Person 执行某些操作时,您希望对 Address 进行级联操作。如果您使用注释,请参阅CascadeType 。

在你的 hbm 中它看起来像 <one-to-one name="Person" class="model_mapowanie_xml.Person" cascade="all"/>


Vla*_*cea 5

使用 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,BookSummary实体只是扩展了BaseBook超类并且不添加额外的实体属性。

@Entity(name = "BookSummary")
@Table(name = "book")
public class BookSummary extends BaseBook<BookSummary> {
 
}
Run Code Online (Sandbox Code Playgroud)

另一方面,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);
    }
}
Run Code Online (Sandbox Code Playgroud)

持久化实体

这样,您可以保留一个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\"" +
            "}"
        )
);
Run Code Online (Sandbox Code Playgroud)

BookSummary

entityManager.persist(
    new BookSummary()
        .setIsbn("978-1934356555")
        .setTitle("SQL Antipatterns")
        .setAuthor("Bill Karwin")
);
Run Code Online (Sandbox Code Playgroud)

获取实体

您可以获取BookSummary实体:

BookSummary bookSummary = entityManager
    .unwrap(Session.class)
    .bySimpleNaturalId(BookSummary.class)
    .load("978-9730228236");
 
assertEquals(
    "High-Performance Java Persistence",
    bookSummary.getTitle()
);
Run Code Online (Sandbox Code Playgroud)

Book实体,如果你想:

Book book = entityManager
    .unwrap(Session.class)
    .bySimpleNaturalId(Book.class)
    .load("978-9730228236");
 
assertEquals(
    "High-Performance Java Persistence, 2nd edition",
    book.getTitle()
);
Run Code Online (Sandbox Code Playgroud)

结论

因此,将多个实体映射到同一个数据库表,不仅可以让我们更有效地获取数据,而且还可以加快脏检查过程,因为 Hibernate 必须检查更少的实体属性。

使用这种方法的唯一缺点是,您必须确保不会为同一个数据库表记录获取多个实体类型,否则,这会在刷新持久性上下文时导致不一致。