For a JPA project I got asked to implement the following situation:
A book can have many authors.
Also there is an UML that states that an author can have many books and a book can have many authors.
I am a beginner when it comes to this subject.
Do I need an many to many relation (with an intersection table)
or do I need a bidirectional one to many relation.
Also the bidirectional part of a one to many relation confuses me. If anybody could explain this with an example that would be nice.
The bidirectional associations allow you to navigate both sides of this relationship both in Object space as well as in JPA/Hibernate Query Language.
In your example, a database many-to-many association is mandatory (meaning you have a BOOK, an AUTHOR and a BOOK_AUTHOR link table). Hibernate offers two possibilities for mapping this relationship:
You can model this with two entities: Book and Author, each one having a #ManyToMany association to the other (one being the owning side while the other being the inverse one)
You can have three entities: Book, Author and BookAuthor and this time Book have a #OneToMany association to BookAuthor and Author has also a #OneToMany association to BookAuthor. This option allows you two map additional link table columns (BOOK_AUTHOR creation_time).
Related
I am trying to build a Book app.
The entities are so-
The Entity User has a field called Role which specifies if this is an Author or Reviewer. Currently, I am using an Enum data member to differentiate if the User is an Author or Reviewer. One single instance of a User cannot be both.
A Book will have 1...* Authors- So a User entity which is an Author will have a many-to-many relation with entity Book
A Book will have 1...* Reviewers- So a User entity which is a Reviewer will have a many-to-many relation with entity Book
I was wondering how would I implement the User side - I preferably want one single collection of Books- If the User is an Author, this will contain a reference to the books he has authored. If it is a reviewer, it will contain references to the books on which he is a reviewer.
I am wondering if there is any construct in JPA/ Hibernate which can enable this.
I could always implement Author and Reviewer as different entities, but I still want to know the answer to such a situation which I presume must be quite commonly encountered.
I am learning persistence with Hibernate (and JPA) on Udemy and the presenter explains an alternative to the previous associations discussed (unidirectional OneToOne, bidirectional OneToOne, Unidirectional OneToMany, bidirectional OneToMany), called the #JoinTable JPA annotation.
He mentions that sometimes only a small selection of the "Many" entities are associated with a specific kind of "One" entities and that we don't want a field on the "Many" entity to embody the association with the "One" entity since that field will remain null for most instances. He goes on to recommend the #JoinTable for this situation.
My question is, considering the effect of the #JoinTable option on the Java entities, why not just use the Unidirectional #OneToMany annotation on the "One" entity and leave the "Many" entity as-is? Which additional features would #JoinTable bring to the situation from within Java beyond what Unidirectional #OneToMany brings?
Then he is clearly wrong, #JoinTable is definitely not necessary here and will introduce overhead in terms of memory (more data to store) and time complexity (another table to join).
You're right about that you only need #JoinColumn to map one-to-one and one-to-many relationships (and mappedBy on the other side if it should be bidirectional).
P.S.: I would consider going further with this course, as it seems to be flawed even with the very basics of jpa.
Recently, I have been learning about Hibernate, and I am facing some difficulties. My first problem is as follows: I am very much confused with the below terms.
Bidirectional mapping
Many to One
Because, as far as I know, in rdbms we first need to insert in parent table. Then we can insert on child table, so the only possible scenario is one-to-many (first parent then children). Then, how is many-to-one is going to work? Second, what is this bidirectional mapping in regards to Hibernate. Specifically, different types of join annotations confuse me a lot. I am listing those annotations below.
1.#JoinTable(name = "Tbale_Name", joinColumns = { #JoinColumn(name = "Column_Name") },
inverseJoinColumns = { #JoinColumn(name = "Another_ColumnName") })
2.#OneToMany(mappedBy="department")` this mappedby term
3.#PrimaryKeyJoinColumn
Please help me understand these concepts.
The first thing I would say is don't think in terms of tables but think in terms of Objects.
What you are trying to express with the annotations is the relationship between objects, let hibernate work out how to persist the data. You can obviously manually check the SQL but the idea of using an ORM is to map the relationships between entities accordingly and let the ORM figure out the complexity around generating SQL etc.
Its worth noting that the parent -> child relation can be mapped using #ManyToOne by adding mappedBy to the non-owning (child) side of the relationship. Hibernate then will determine which entities to insert into the database first. Running with a TransactionManager will enforce integrity with multi table inserts. Hibernate will also workout which entities need to be persisted, for example if you add an new object on the many side to an existing object on the one side.
Furthermore, its worth understanding that in some cases it won't always be the database that generates the primary key in a parent -> child foreign key. Its possible for the code to generate the Identifier and hibernate will persist them according.
Bidirectional mapping means that object entities have a reference to each other. i.e. You can retrieve the second entity from the first entity. Bidirectional mapping supports one-to-many
or many-to-many. I.e. OneToMany = a Set on one of the entities. Many-To-Many = Sets on both entities.
JoinTable tells hibernate that a table in the database can be used to map to other tables together. See JPA "#JoinTable" annotation for more information. JoinColumn tells hibernate what column to use to make the join between the two entities. Hibernate needs these to construct the SQL.
The below definition is taken from Hibernate association mapping tutorial here
Each book is related to one publisher while one publisher may publish many books.
I'd represent the above definition the below way in Java
class Book
{
Publisher pub;
}
class Publisher
{
Set<Book> books;
}
Question 1. Now I am confused as to why the tutorial says The association from book to publisher is called a “many-to-one” association. I thought There is a "one-to-many" association between the publisher and the book would have been the right approach.
Question 2. Below is the hbm for Book. Why shouldn't we declare a one-to-many in the Publisher's hbm mapping. What determines the location for this relationship mapping?
<class name="Book" table="BOOK">
<many-to-one name="publisher" class="Publisher" column="PUBLISHER_ID" />
</class>
it depends on whether the relationship is bidirectional. See section 7.3.2 here http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/collections.html#collections-mapping.
a bidirectional relationship is when you can go from both the parent to the child (i.e. Publisher -> Book) and from child to parent (i.e. Book -> Publisher). The parent to child is a one-to-many, while the child to parent is a many-to-one.
Note you do not need bidirectional relationships. The 'right approach' depends exactly on what your application needs. If you need to only go from pu.lisher to book, you only need a one to many. If you only need to go from books to publisher, that you just need the many to one. If you need both, you can have both (i.e. make the relationship bidirectional)/
The association from Book to Publisher is many-to-one because there can be many books per publisher. This is irrelevant to the that fact that Book is only aware of its own Publisher. The association is to aid Hibernate in understanding the underlying representation.
There is nothing wrong with also declaring a one-to-many relationship from Publisher to Book. You can have both present. It depends on your data model and how you plan on interacting with it.
Question 1: Actually both are correct. It depends on the direction of the relationship. Many books belong to one publisher results in a many to one relationship from the book side.
Question 2: If you are interested in a bi-directional relationship then you can actually place a one to many on one side and a many to one on the other. However, you have to be careful to use the mappedBy attribute to ensure that hibernate knows that its the same relationship being defined from both ends.
A relationship can be unidirectional, or bidirectional.
The way you designed it in your Java code, it's bidirectional. This means that the same physical relationship (materialized by the foreign key) is viewed as two logical relationships :
from the book point of view : several books are published by one publisher (ManyToOne)
from the publisher point of view : one publisher publishes several books (OneToMany)
The XML mapping you show in your question describes one side of the relationship. But if you want to make it bidirectional, you must also declare the other side. One of the sides is declared as the inverse of the other.
Hibernate gives you the choice : you could have a collection of books in the publisher class (unidirectional one to many), or a publisher reference in the book class (unidirectional many to one), or both (bidirectional one to many/many to one).
Read the documentation for more details.
I have two tables (folder and document) which have a many to many relationship with a join table in between, this join table then also has another one to many relationship with a third table (document_title).
I want to be able to fetch a document_title from a document, what is the correct way to model this in hibernate?
The object model needs to be a Document that contains a DocumentTitle instance.
Thanks
I'm afraid what you're trying to do does not fit nicely into into OO world. I'd introduce thrid entity class as in-between. This third class can contain any attributes you like. So insted of many-to-many you would have two one-to-many relationships (or one-to-many and many-to-one).