Firstly, I have read Hibernate - One table with multiple entities?.
However, I would like to map two entities to the same table, but I would like both of them to be entities, which I can select from. What I mean:
So it's a 1:1 relationship between Entities, but still 1 table in DB.
If I do it using the proposed solution (component keyword) in the above link, I can't query Address directly (I can access it via Person entity). And I want to be able to do
session.createCriteria(Adres.class)
How do I do that?
UPDATE: I tried the one-to-one association between entities, in Address mapping:
<one-to-one name="Person " class="model_mapowanie_xml.Person "/>
and in Person mapping:
<one-to-one name="Address" class="model_mapowanie_xml.Address "/>
Both classes have fields referring to the other one. Selecting records works fine for that. However, how can I add in one transaction a record using both entities? (Id is db-generated)
Address ad = new Address();
ad.setProperty("Sydney");
Person p = new Person();
p.setProperty("John");
p.setAddress(ad);
session.save(p);
and only Person part is saved, the address property remains empty.
This is very simple to achieve with JPA and Hibernate.
Let's assume you are using the following book
database table:
Now, you can map two entities: Book
and BookSummary
to this table.
First, we will create a BaseBook
abstract class which will be extended by all entities:
@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;
}
}
Now, the BookSummary
entity simply extends the BaseBook
superclass and adds no additional entity attribute.
@Entity(name = "BookSummary")
@Table(name = "book")
public class BookSummary extends BaseBook<BookSummary> {
}
On the other hand, the Book
entity extends the BaseBook
superclass and maps the properties
attribute.
@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);
}
}
This way, you can persist either a Book
entity:
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\"" +
"}"
)
);
or a BookSummary
:
entityManager.persist(
new BookSummary()
.setIsbn("978-1934356555")
.setTitle("SQL Antipatterns")
.setAuthor("Bill Karwin")
);
You can fetch the BookSummary
entity:
BookSummary bookSummary = entityManager
.unwrap(Session.class)
.bySimpleNaturalId(BookSummary.class)
.load("978-9730228236");
assertEquals(
"High-Performance Java Persistence",
bookSummary.getTitle()
);
or the Book
entity if you want:
Book book = entityManager
.unwrap(Session.class)
.bySimpleNaturalId(Book.class)
.load("978-9730228236");
assertEquals(
"High-Performance Java Persistence, 2nd edition",
book.getTitle()
);
So mapping multiple entities to the same database table, not only that it allows us to fetch data more efficiently, but it also speeds up the dirty checking process as Hibernate has to inspect fewer entity properties.
The only drawback of using this approach is that you have to make sure you don’t fetch more than one entity type for the same database table record, as otherwise, this can cause inconsistencies when flushing the Persistence Context.
You should be able to do it using @Table
annotation. These entites will be treated as different entites but will be mapped onto same table.
@Entity
@Table(name="PERSON_TABLE")
class Person {}
@Entity
@Table(name"PERSON_TABLE")
class Address {}
Edit:
If you want to save both entities in one transaction you either have to explicitly save them using Session
or set cascade
property to cascade operations on relationship. I guess you want to cascade operations on Address when you do something on Person. See CascadeType if you use annotations.
In your hbm it would look like
<one-to-one name="Person" class="model_mapowanie_xml.Person" cascade="all"/>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With