web-dev-qa-db-fra.com

Comment mapper deux entités JPA ou Hibernate sur la même table de base de données

Dans notre projet, nous avons une entité "Restaurant" avec près de 30 champs (certains ont des relations avec d'autres entités). Ainsi, chaque fois que nous avons besoin d'un objet "Restaurant", même pour quelques champs, tous les autres sont récupérés. Cela affecte les performances. Ainsi, dans le fichier HBM, nous avons écrit deux classes pointant toutes les deux vers la même classe physique et la même table de base de données, comme indiqué ci-dessous.

=== 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>

Dans l'une des implémentations DAO, nous utilisons des critères qui prennent "RestaurantLite" et retournent la liste des restaurants comme indiqué ci-dessous.

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

   // criteria related stuff

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

Maintenant, nous voulons supprimer tous les fichiers hbm et utiliser des annotations. Alors, comment faire la même chose en utilisant des annotations pour les entites? Avons-nous besoin de créer une classe supplémentaire "RestaurantLite"? Si alors, comment les critères ci-dessus renvoient-ils les objets "Restaurant" ??

25
Raj44

Puisque c'est une question très courante, j'ai décidé d'écrire un article détaillé à ce sujet.

Pour résumer, les mappages suivants vont montrer comment vous pouvez mapper plusieurs entités à la même table de base de données:

@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;
    }
}

Et Hibernate fonctionnera très bien:

@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. PostSummary est juste une vue en lecture seule sur votre entité d'origine, donc je l'ai annotée avec @Immutable.

  2. UpdatablePostSummary est marqué par @DynamicUpdate et vous pouvez ainsi propager les modifications à partir de cette entité View également.

Ce test est également disponible sur GitHub .

46
Vlad Mihalcea