Understanding bidirectional relationship from Hibernate documentation - java

I am going through the Hibernate documentation for bidirectional relationship, in the doc it says that:
Example 7.21. Bidirectional one to many with many to one side as association owner
#Entity
public class Troop {
#OneToMany(mappedBy="troop")
public Set<Soldier> getSoldiers() {
...
}
#Entity
public class Soldier {
#ManyToOne
#JoinColumn(name="troop_fk")
public Troop getTroop() {
...
}
Troop has a bidirectional one to many relationship with Soldier
through the troop property. You don't have to (must not) define any
physical mapping in the mappedBy side.
To map a bidirectional one to many, with the one-to-many side as the
owning side, you have to remove the mappedBy element and set the many
to one #JoinColumn as insertable and updatable to false. This solution
is not optimized and will produce additional UPDATE statements.
Example 7.22. Bidirectional association with one to many side as owner
#Entity
public class Troop {
#OneToMany
#JoinColumn(name="troop_fk") //we need to duplicate the physical information
public Set<Soldier> getSoldiers() {
...
}
#Entity
public class Soldier {
#ManyToOne
#JoinColumn(name="troop_fk", insertable=false, updatable=false)
public Troop getTroop() {
...
}
I am finding difficulty in understanding this as I am new to Hibernate.
1) What it means when the doc says:
You don't have to (must not) define any physical mapping in the mappedBy side.
2) #JoinColumn in 7.22 has same value (troop_fk) for name attribute. Can we specify different values? What is the advantage & disadvantages of setting insertable=false, updatable=false here?
Can someone please explain?

It's a bidirectional association. So, if a soldier balongs to a troop, the troop contains the soldier. These are just the two ways of saying the same thing.
In Soldier, you tell how the association is represented in the database: using a join column named troop_fk:
#JoinColumn(name="troop_fk")
public Troop getTroop() {
So, repeating that same information on the other side of this bidirectional association is redundant. You must not do it. By saying
#OneToMany(mappedBy="troop")
public Set<Soldier> getSoldiers() {
you're telling Hibernate that getSoldiers() is the inverse side of a bidirectional association, and that the way this association is mapped can be found on the Soldier.troop property.
Regarding your second question. Once again, the goal is to define a single, but bidirectional association. You don't need two different foreign keys to map a single association. So specifying a different name for the join column would make no sense: it would create a different, unidirectional association.
This way of doing is an ugly hack that, AFAIK, is not supported by the JPA spec. The JPA spec mandates that the owner side of a bidirectional OneToMany association is the many side. In fact it creates two unidirectional associations mapped the same way, and tells Hibernate (using insertable = false and updatable = false) to ignore one of them when saving the entity. It will populate soldier.troop when reading a soldier from the database, but whatever you put into soldier.troop will be ignored when saving the soldier. You should avoid this way of doing, IMHO.

Related

Hibernate: How to distinguish two uni-directional relationship and one bi-directional relationship?

in this answer, the author said:
Take an example of two entities mapped without declaring a owning
side:
#Entity
#Table(name="PERSONS")
public class Person {
#OneToMany
private List<IdDocument> idDocuments;
}
#Entity
#Table(name="ID_DOCUMENTS")
public class IdDocument {
#ManyToOne
private Person person;
}
From a OO point of view this mapping defines not one bi-directional
relation, but two separate uni-directional relations.
1.My first question is:
Why it is not a bi-directional relation?
Docs Oracle:
In a bidirectional relationship, each entity has a relationship field
or property that refers to the other entity. Through the relationship
field or property, an entity class’s code can access its related
object
in the above code, both class have a relationship field that refers to the other entity. then why it is not a bi-directional relation and these are two uni-directional relations?
2.My second question is: what is the difference between two uni-directional relations and one bi-directional relation? aren't they same thing?
(1) No ideas why the author said it is not a bi-directional relationship.
From the hibernate documentation , it also mentions that a similar mapping is a bidirectional which both involved entities can navigate to each other.
In this example, given a Person , we can get its IdDocument by its idDocuments field. And given an IdDocument , we can get its Person by its person field. So it is a bi-directional.
(2) I am not sure too. To me, whenever both entities in a relationship can navigate to each other , it is a bi-directional relationship. If only one entity can navigate to another but not vice versa , it is a unidirectional relationship.
And you can find the equivalent unidirectional case of the example the I mentioned above in this for comparing their differences.

why One-To-Many association cannot be Bidirectional and it should just be Unidirectional?

I'm trying to learn about JPA and Hibernate and I was trying to learn about some database terms.
In a video on youtube, the teacher (at 2:42) said:
One-To-Many is only Unidirectional.
and she said suppose thsese two class:
class Person {
List<Address> addresses;
}
class Address {
Person p;
}
and she said:
this is One-To-Many. but Address cannot have a collection of Person
because if it has a collection of Person, it's going to be
Many-To-Many.
but I think she is not right, because we can have these two:
thePerson.getAddresses().get(i);
and
anAddress.getPerson();
When we can have these two statements, then it is Bidirectional. Then why she said it can be just Unidirectional?
What is Bidirectional's exact definition with which she came to such a conclusion?
First of all, any relationship can be unidirectional or bidirectional, it's all depend on how you want to display or retrieve your data, and your business rules.
When we can have these two statements, then it is Bidirectional. Then
why she said it can be just Unidirectional?
There is also a big mismatch between the object oriented approach of ORMs like Hibernate and how tables and relationships are defined in a relational database. She can be wright, because, in the point of view of a database, relationships are by default unidirectional.
The difference between unidirectional and bidirectional is defined by the fact that you can access the records of the other side of your relationship from where you are.
What is Bidirectional's exact definition with which she came to such a
conclusion?
In your example we can interpret your relationship like this:
Unidirectional: you can get all your addresses from person, but not the inverse
class Person {
#OneToMany
List<Address> addresses;
}
class Address {
// Here you don't add the ManyToOne
Person p;
}
Bidirectional: you can get all your addresses from person and get a person from an address
class Person {
#OneToMany
List<Address> addresses;
}
class Address {
#ManyToOne
Person p;
}
Take a look at those links below:
Difference between unidirectional and bidirectional relational relationship
https://www.baeldung.com/spring-data-rest-relationships
What is Object/Relational mismatch
You are correct, she's not right. All kinds of relationships can de unidirectional or bidirectional.
On the child side, you have to annotate the field with #JoinColumn.
On the parent side, you have to use the property mappedBy of #OneToMany annotation.
Example:
#OneToMany(mappedBy = "user")
private List<Address> addresses;
#ManyToOne
#JoinColumn
private User user;
Here's a good lecture about it.
https://vladmihalcea.com/the-best-way-to-map-a-onetomany-association-with-jpa-and-hibernate/

What is #OneToOne mapping in spring JPA?

I am new to Spring data jpa and trying to understand #OneToOne mapping.
Let's say I have a Employee entity and a Company Entity, If I want to map these 2 entities, then I can use one to one mapping on Employee entity which means one employee can belong to one company only.
Is this understanding wrong?
If one employee belongs to one company(lets say XYZ) then the company(XYZ) cannot be mapped to a different employee?
I have read few posts but not completely understood.
#OneToOne represents that there is only one Object of Entity related to the other Entity
if we have Employee and Passport Entity so only One Passport related to One Employee
and for sure one One Object of Employee related to One Object from Passport
#Entity
Public class Employee
{
#OneToOne
private Passport passport;
}
so from Employee i can get his Passport
#Entity
Public class Passport
{
#OneToOne
private Employee employee;
}
and from Passport i can get The Employee.
Mapping is nothing but defining the relationship between two entities/objects and it is just like stating 5>4, 10=10, 6<8. The numbers here (5,4,10,6 and 8) are the entities and the symbols (>, = and <) are the relationships/mapping between them.
We do the same with mappings in hibernate. Note down the two entities and put in between them the relationship (mapping) them in the way it makes more sense.
Father OneToMany Child (Father can be One, To Many child/children)
Child ManyToOne Father (Child/Children can be Many, To One Father)
Employee ManyToOne Company (Employee can be Many, To One Company)
Company OneToMany Employees (Company can be One, To Many Employee(s))
Address OneToOne Employee (Address can be One, To One Employee)
Employee OneToOne Address (Employee can be One, To One Address)
The relationship should make sense. Which means it should make sense when you look at the relationship from each of the both sides of the relationships (One child Many Fathers doesnt make sense but One Father many child/children does)
Say an employee can be mapped to a Company that is one to one mapping keeping Employee as owner of the relationship. Whereas if you view Company as owner of the relationship, that it is One to Many.
Case 1 : Employee as Owner
#Entity
Public class Employee
{
#ManyToOne
private Company company;
......
}
#Entity
Public class Company
{
#OneToMany(mappedBy="company") \\ mappedBy is used to say that Employee is owner and
\\it should match variable name company
private List<Employee> employee;
......
}
Yes, you are correct.
If you want the Company to have multiple Employees, then you want a ManyToOne relationship between Employee and Company, and a OneToMany relationship between the Company and employee.
Actually, in this case, You must use one to many relationship.
you can simply use the #ManytoOne annotation in Company Entity that related to Employee Entity.
Specifies a single-valued association to another entity class that has many-to-one multiplicity. It is not normally necessary to specify the target entity explicitly since it can usually be inferred from the type of the object being referenced. If the relationship is bidirectional, the non-owning OneToMany entity side must used the mappedBy element to specify the relationship field or property of the entity that is the owner of the relationship.
Visit https://en.wikibooks.org/wiki/Java_Persistence/ManyToOne for more information and samples.

Spring/Hibernate: Bidirectional Mapping without synchronization for JPQL queries only

In a bidirectional mapping between entities (e.g. #ManyToOne ↔ #OneToMany), the counterpart needs to be synchronized on every change, especially when using a 2nd level cache. This is usually done with helper methods. Those helper methods do not perform well if the Many part contains a lot of entries, because the whole set is fetched each time. A simple example would be an entity Store which has n Products, whereas n is very large. Adding a new Product to the Store would require the Store to fetch the whole list of Products to finally add it to the set (see code example below).
One could argue, that when modelling such a relation it would be better represented with an unidirectional association from the Product to the Store. We are using many JPQL queries in our application though. In JPQL, it comes very handy to join entities from both sides.
Do you see any problems when mapping the #OneToMany relation in the Store entity, when Many actually means many and not just a few, and just make the field private, without getters and setters, provided that the whole relation is lazily fetched? As I understand, Hibernate just needs the field to map the relation. And if the set is private, no performance issues should occur?
The Product entity:
#Entity
#Table(name = "product")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Product {
#ManyToOne(fetch = FetchType.LAZY)
private Store store;
// setter, getter, helper methods
}
The Store entity:
#Entity
#Table(name = "store")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Store {
#OneToMany(mappedBy = "products", fetch = FetchType.LAZY)
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
private Set<Product> products;
// setter, getter, helper methods
}
No, there is nothing wrong with it, it's a technique I've used often as well. Of course just make sure that the field is not accessed reflectively in some context (like automatic toString builders and similar utilities you may be using).
Also, you don't need the #Cache annotation on it since you will never access the collection anyway, thus it will never be cached.

EJB3 mapped by? whose owning of OR mapping?

Hello everybody i wonder: when can i use mapped by to indicate whose is owing of relationship in one-to -one or one to many - or many to many relationship mapping with EJB3 (JPA)
example
i have two table A and B
table A belong to table B
so what i place mapped by for whose table?
when can I use mapped by to indicate whose is owing of relationship in one-to -one or one to many - or many to many relationship mapping with EJB3
A relationship can be unidirectional or bidirectional. Within a bidirectional relationship you must specify the owning side of the relationship in the other class with the mappedBy element.
The owning side which is responsible for propagating the update of the relationship to the database. Usually this is the side with the foreign key.
The inverse side maps to the owning side.
From the JPA 1.0 specification:
2.1.7 Entity Relationships ...
Relationships may be bidirectional or
unidirectional. A bidirectional
relationship has both an owning side
and an inverse side. A unidirectional
relationship has only an owning side.
The owning side of a relationship
determines the updates to the
relationship in the database, as
described in section 3.2.3.
The following rules apply to
bidirectional relationships:
The inverse side of a bidirectional relationship must refer to its owning
side by use of the mappedBy element
of the OneToOne, OneToMany, or
ManyToMany annotation. The
mappedBy element designates the
property or field in the entity that
is the owner of the relationship.
The many side of one-to-many / many-to-one bidirectional
relationships must be the owning side,
hence the mappedBy element cannot be
specified on the ManyToOne annotation.
For one-to-one bidirectional relationships, the owning side
corresponds to the side that contains
the corresponding foreign key.
For many-to-many bidirectional relationships either side may be the
owning side.
Imagine the following model:
#Entity
public class Player {
...
private Team team;
#ManyToOne
public Team getTeam() { return team; }
...
}
And
#Entity
public class Team {
...
private Set<Player> players = new HashSet<Player();
public Team() { }
#OneToMany(mappedBy = "team")
public Set<Player> getPlayers() { return players; }
...
}
In this example, the mappedBy attribute shows that a Player instance's team property maps to the Team instance and the Team object's identifier will exist as a foreign key column in the PLAYER table. The owning Player side of the relationship is responsible for storing the foreign key.
If the mappedBy is not used, the persistence provider will assume that there are two independent relationships:
Which is generally not what you want and might end up getting unexpected behavior (e.g. duplicate rows inserted with many-to-many).
Related questions
In a bidirectional JPA OneToMany/ManyToOne association, what is meant by “the inverse side of the association”?
JPA: which side should be the owning side in a m:n relationship?
References
JPA 1.0 specification
Section 2.1.7 "Entity Relationships"
The mappedBy attribute can be used when the relationship is already define on the other part.
For example, in a One to One relationship between entities A and B:
#Entity
public class A {
#OneToOne
#JoinColumn
private B b;
// Code removed for clarity
}
Here, my A class defines the relationship to B. It is a One to One relationship using a join column. If I want B to be linked to A, using this already defined relationship, to establish a bidirectional relationship between my entities, I can use the mappedBy attribute :
#Entity
public class B {
#OneToOne(mappedBy="b")
private A a;
// Code removed for clarity
}
Here, the mappedBy attribute means "I want to defined a One to One relationship, which has already been defined on entity A, on the attribute called 'b'".
In general, the owning side of a bidirectional relationship is the entity mapped to the table containing the join column referencing the other table. In case you are using a join table, any side can be the owning side, it just has to make sense in your data model.

Categories

Resources