Hibernate - 一个表多个实体

时间:2013-08-31 12:04:39

标签: sql hibernate

首先,我已阅读Hibernate - One table with multiple entities?

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

  • 一张桌子:人(身份证,姓名,日期,生日,城市,街道,邮政编码)。
  • 两个实体:人(id,name,dateOfBirth),地址(id,city, 街道,邮政编码)。

所以它是实体之间的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部分,地址属性保持为空。

2 个答案:

答案 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数据库表:

enter image description here

映射实体

现在,您可以将两个实体:BookBookSummary映射到此表。

首先,我们将创建一个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必须检查较少的实体属性,因此它还加快了脏检查过程。

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