Reputation: 268
I'm working with a database with many joins. I'd like to have some tables represented by two or more different entities, with and without joins. This is a simplified example:
VERSION WITH JOINS
@Entity
@Table(name = "books")
public class Book{
@Id
private Integer id;
@Column(name = "title")
private String title;
@ManyToOne
@JoinColumn(name = "author_id", foreignKey = @ForeignKey(name = "id"))
private @NotNull Author author; // the class Author is an entity for the table "authors"
}
VERSION WITHOUT JOINS
@Entity
@Table(name = "books")
public class BookWithDetails{
@Id
private Integer id;
@Column(name = "title")
private String title;
@Column(name = "author_id")
private Integer authorId;
}
I want to build an API that allows me to retrieve the details only when I need them. For example:
/api/books/123
{
"id": 123,
"title": "The Lord of the Rings",
"authorId": 321
}
/api/books/123/details
{
"id": 123,
"title": "The Lord of the Rings",
"author": {
"name": "John Ronald Reuel",
"surname": "Tolkien"
}
}
The ideal solution would be having BookWithDetails
extend Book
and, in the book/author example, having the Author author
replacing Integer authorId
(but having both would be fine too).
I can't get this to work as both entities refer to the same table and Hibernate automatically search for a dtype
discriminant column which does not exist.
I searched for similar questions and tried many solutions but none of them fit my needs, mostly because they require the use of a discriminator column or they are about different tables sharing common fields.
Any ideas?
Upvotes: 1
Views: 10947
Reputation: 16400
It's not a good idea to have multiple entities referring to the same table. You can make use of the immutable entity concept Hibernate offers, but that will only get you that far.
I think this is a perfect use case for Blaze-Persistence Entity Views.
I created the library to allow easy mapping between JPA models and custom interface or abstract class defined models, something like Spring Data Projections on steroids. The idea is that you define your target structure(domain model) the way you like and map attributes(getters) via JPQL expressions to the entity model.
A DTO model for your use case could look like the following with Blaze-Persistence Entity-Views:
@EntityView(Books.class)
public interface BookWithoutDetails {
@IdMapping
Integer getId();
String getTitle();
@Mapping("author.id")
Integer getAuthorId();
}
@EntityView(Books.class)
public interface BookWithDetails {
@IdMapping
Integer getId();
String getTitle();
AuthorDto getAuthor();
@EntityView(Author.class)
interface AuthorDto {
@IdMapping
Long getId();
String getName();
}
}
Querying is a matter of applying the entity view to a query, the simplest being just a query by id.
BookWithDetails a = entityViewManager.find(entityManager, BookWithDetails.class, id);
The Spring Data integration allows you to use it almost like Spring Data Projections: https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features
List<BookWithDetails> findAll();
Upvotes: 3
Reputation: 1292
It does not make sense to have two entities for the same table, it is also a vulnerability to directly expose the entities in the API, use a framework like Orika and create plain objects to send.
You could create two different mappers to have with and without details.
Upvotes: 1