Java 如何在同一个数据库表上映射两个 JPA 或 Hibernate 实体

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/29007676/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 07:11:24  来源:igfitidea点击:

How to map two JPA or Hibernate entities on the same database table

javadatabasespringhibernatejpa

提问by Raj44

In our project, we have an entity 'Restaurant' with nearly 30 fields(some have relationships with other entities). So, every time we need a 'Restaurant' object even for a few fields, all the others are retrieved. This effects the performance. So, in the HBM file, we wrote two classes both pointing to the same physical class and same database table, as shown below.

在我们的项目中,我们有一个包含近 30 个字段的实体“餐厅”(有些与其他实体有关系)。因此,每次我们需要一个 'Restaurant' 对象时,即使是几个字段,所有其他字段都会被检索。这会影响性能。因此,在 HBM 文件中,我们编写了两个类,它们都指向同一个物理类和同一个数据库表,如下所示。

=== restaurant.hbm.xml ===
<!-- Light Weight Version -->
<class name="com.raj.model.Restaurant" table="RESTAURANTS" entity-name="RestaurantLite" 
                dynamic-update="false" dynamic-insert="false">
<cache usage="read-only"/>
     <!-- few basic properties and relationships -->
</class>

<!-- Restaurant -->
<class name="com.raj.model.Restaurant" table="RESTAURANTS" entity-name="Restaurant">
     <!-- all properties and relationships -->
</class>

In one of the DAO implementations, we are using Criteria which takes 'RestaurantLite' and returning list of restaurants as shown below.

在 DAO 实现之一中,我们使用 Criteria,它采用“RestaurantLite”并返回餐厅列表,如下所示。

Criteria criteria = session.createCriteria("RestaurantLite");

   // criteria related stuff

return new LinkedHashSet<Restaurant>(criteria.list());

Now we want to remove all hbm files and use annotations. So how the same can be done using annotations for entites? Do we need to create an extra class 'RestaurantLite'? If then, how the above criteria returns 'Restaurant' objects??

现在我们要删除所有 hbm 文件并使用注释。那么如何使用实体的注释来完成同样的事情呢?我们是否需要创建一个额外的类“RestaurantLite”?如果是这样,上述标准如何返回“餐厅”对象?

回答by Fabien I

You have to add annotation @Entity,@Table(name="RESTAURANT") on your class, add annotations and replace your detailed mapping in hbm file by
.

您必须在类上添加注释 @Entity,@Table(name="RESTAURANT"),添加注释并将 hbm 文件中的详细映射替换为
.

Here a complete example: http://viralpatel.net/blogs/hibernate-many-to-many-annotation-mapping-tutorial/

这里有一个完整的例子:http: //viralpatel.net/blogs/hibernate-many-to-many-annotation-mapping-tutorial/

回答by Vlad Mihalcea

Since this is a very common question, I decided to write a detailed articleabout it.

由于这是一个非常常见的问题,我决定写一篇详细的文章

To summarize it, the following mappings are going to demonstrate how you can map multiple entities to the same database table:

总而言之,以下映射将演示如何将多个实体映射到同一个数据库表:

@Entity(name = "Post")
public class Post {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private Long id;

    private String name;

    private String description;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }
}

@Entity(name = "PostSummary")
@Table(name = "Post")
@Immutable
public class PostSummary {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

@Entity(name = "UpdatablePostSummary")
@Table(name = "Post")
@DynamicUpdate
public class UpdatablePostSummary {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

And Hibernate will work just fine:

并且 Hibernate 可以正常工作:

@Test
public void testOneTableMultipleEntities() {
    doInTransaction(session -> {
        Post post = (Post) session.get(Post.class, 1L);
        PostSummary postSummary = (PostSummary) session.get(PostSummary.class, 1L);
        UpdatablePostSummary updatablePostSummary = (UpdatablePostSummary) session.get(UpdatablePostSummary.class, 1L);
        assertEquals(post.getName(), postSummary.getName());
        assertEquals(post.getName(), updatablePostSummary.getName());
        updatablePostSummary.setName("Hibernate Master Class Tutorial.");
    });
}
  1. The PostSummaryis just a read-only View over your original entity, hence I annotated it with @Immutable.

  2. The UpdatablePostSummaryis marked with @DynamicUpdateand so you can propagate changes from this View entity too.

  1. PostSummary只是原始实体的只读视图,因此我用@Immutable.

  2. UpdatablePostSummary标有@DynamicUpdate,所以你可以传播从这个视图实体变化太大。

This test is also available on GitHub.

此测试也可在GitHub 上获得

回答by thmayr

I have a similar Problem. I have two classes, the base class DocumentContentand a derived class DocumentContentWithData:

我有一个类似的问题。我有两个类,基类DocumentContent和派生类DocumentContentWithData

DocumentContent {
    private Long documentContentId;
    private InputStream contentStream;
    private File importFile;
    ... and several other attributes
}

DocumentContentWithData extends DocumentContent {}

I defined a hibernate mapping for the two classes, for the class DocumentContenta mapping without the contentStreamand for the class DocumentContentWithDataa mapping with the contentStream.

我为这两个类定义了一个休眠映射,对于类DocumentContent是一个没有contentStream的映射,对于类DocumentContentWithData是一个与contentStream的映射。

Saving the data with the class DocumentContentWithDataworks and also getting the instances for both classes works with the method Session.get(Class, ID).

使用类DocumentContentWithData保存数据,并且使用Session.get(Class, ID)方法获取两个类的实例。

However the query in the following code returns two entities, one as instance of DocumentContentand the other as instance of DocumentContentWithDataalthough there is only one entry with the importFilein the database:

然而,在下面的代码返回两个实体,一个作为实例查询DocumentContent和其他作为实例DocumentContentWithData虽然只有一个与该入口的importfile数据库:

CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder();
CriteriaQuery<DocumentContent> criteriaQuery = criteriaBuilder.createQuery(DocumentContent.class);
Root<DocumentContent> root = criteriaQuery.from(DocumentContent.class);
criteriaQuery.select(root).where(criteriaBuilder.equal(root.get("importFile"), importFile));
Query<DocumentContent> query = session.createQuery(criteriaQuery);
List<DocumentContent> contentList = query.getResultList();

Can someone explain this behavior. When I do not derive the class DocumentContentWithDatafrom DocumentContentand duplicate all attributes it works. However this is not a very nice solution.

有人可以解释这种行为。当我不派生类DocumentContentWithDataDocumentContent和复制所有属性,它的工作原理。然而,这不是一个很好的解决方案。