What is the difference between:
#Entity
public class Company {
#OneToMany(cascade = CascadeType.ALL , fetch = FetchType.LAZY)
#JoinColumn(name = "companyIdRef", referencedColumnName = "companyId")
private List<Branch> branches;
...
}
and
#Entity
public class Company {
#OneToMany(cascade = CascadeType.ALL , fetch = FetchType.LAZY,
mappedBy = "companyIdRef")
private List<Branch> branches;
...
}
The annotation #JoinColumn indicates that this entity is the owner of the relationship (that is: the corresponding table has a column with a foreign key to the referenced table), whereas the attribute mappedBy indicates that the entity in this side is the inverse of the relationship, and the owner resides in the "other" entity. This also means that you can access the other table from the class which you've annotated with "mappedBy" (fully bidirectional relationship).
In particular, for the code in the question the correct annotations would look like this:
#Entity
public class Company {
#OneToMany(mappedBy = "company",
orphanRemoval = true,
fetch = FetchType.LAZY,
cascade = CascadeType.ALL)
private List<Branch> branches;
}
#Entity
public class Branch {
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "companyId")
private Company company;
}
#JoinColumn could be used on both sides of the relationship. The question was about using #JoinColumn on the #OneToMany side (rare case). And the point here is in physical information duplication (column name) along with not optimized SQL query that will produce some additional UPDATE statements.
According to documentation:
Since many to one are (almost) always the owner side of a bidirectional relationship in the JPA spec, the one to many association is annotated by #OneToMany(mappedBy=...)
#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 some additional UPDATE statements.
#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() {
...
}
Unidirectional one-to-many association
If you use the #OneToMany annotation with #JoinColumn, then you have a unidirectional association, like the one between the parent Post entity and the child PostComment in the following diagram:
When using a unidirectional one-to-many association, only the parent side maps the association.
In this example, only the Post entity will define a #OneToMany association to the child PostComment entity:
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
#JoinColumn(name = "post_id")
private List<PostComment> comments = new ArrayList<>();
Bidirectional one-to-many association
If you use the #OneToMany with the mappedBy attribute set, you have a bidirectional association. In our case, both the Post entity has a collection of PostComment child entities, and the child PostComment entity has a reference back to the parent Post entity, as illustrated by the following diagram:
In the PostComment entity, the post entity property is mapped as follows:
#ManyToOne(fetch = FetchType.LAZY)
private Post post;
The reason we explicitly set the fetch attribute to FetchType.LAZY is because, by default, all #ManyToOne and #OneToOne associations are fetched eagerly, which can cause N+1 query issues.
In the Post entity, the comments association is mapped as follows:
#OneToMany(
mappedBy = "post",
cascade = CascadeType.ALL,
orphanRemoval = true
)
private List<PostComment> comments = new ArrayList<>();
The mappedBy attribute of the #OneToMany annotation references the post property in the child PostComment entity, and, this way, Hibernate knows that the bidirectional association is controlled by the #ManyToOne side, which is in charge of managing the Foreign Key column value this table relationship is based on.
For a bidirectional association, you also need to have two utility methods, like addChild and removeChild:
public void addComment(PostComment comment) {
comments.add(comment);
comment.setPost(this);
}
public void removeComment(PostComment comment) {
comments.remove(comment);
comment.setPost(null);
}
These two methods ensure that both sides of the bidirectional association are in sync. Without synchronizing both ends, Hibernate does not guarantee that association state changes will propagate to the database.
Which one to choose?
The unidirectional #OneToMany association does not perform very well, so you should avoid it.
You are better off using the bidirectional #OneToMany which is more efficient.
I disagree with the accepted answer here by Óscar López. That answer is inaccurate!
It is NOT #JoinColumn which indicates that this entity is the owner of the relationship. Instead, it is the #ManyToOne annotation which does this (in his example).
The relationship annotations such as #ManyToOne, #OneToMany and #ManyToMany tell JPA/Hibernate to create a mapping. By default, this is done through a seperate Join Table.
#JoinColumn
The purpose of #JoinColumn is to create a join column if one does
not already exist. If it does, then this annotation can be used to
name the join column.
MappedBy
The purpose of the MappedBy parameter is to instruct JPA: Do NOT
create another join table as the relationship is already being mapped
by the opposite entity of this relationship.
Remember: MappedBy is a property of the relationship annotations whose purpose is to generate a mechanism to relate two entities which by default they do by creating a join table. MappedBy halts that process in one direction.
The entity not using MappedBy is said to be the owner of the relationship because the mechanics of the mapping are dictated within its class through the use of one of the three mapping annotations against the foreign key field. This not only specifies the nature of the mapping but also instructs the creation of a join table. Furthermore, the option to suppress the join table also exists by applying #JoinColumn annotation over the foreign key which keeps it inside the table of the owner entity instead.
So in summary: #JoinColumn either creates a new join column or renames an existing one; whilst the MappedBy parameter works collaboratively with the relationship annotations of the other (child) class in order to create a mapping either through a join table or by creating a foreign key column in the associated table of the owner entity.
To illustrate how MapppedBy works, consider the code below. If MappedBy parameter were to be deleted, then Hibernate would actually create TWO join tables! Why? Because there is a symmetry in many-to-many relationships and Hibernate has no rationale for selecting one direction over the other.
We therefore use MappedBy to tell Hibernate, we have chosen the other entity to dictate the mapping of the relationship between the two entities.
#Entity
public class Driver {
#ManyToMany(mappedBy = "drivers")
private List<Cars> cars;
}
#Entity
public class Cars {
#ManyToMany
private List<Drivers> drivers;
}
Adding #JoinColumn(name = "driverID") in the owner class (see below), will prevent the creation of a join table and instead, create a driverID foreign key column in the Cars table to construct a mapping:
#Entity
public class Driver {
#ManyToMany(mappedBy = "drivers")
private List<Cars> cars;
}
#Entity
public class Cars {
#ManyToMany
#JoinColumn(name = "driverID")
private List<Drivers> drivers;
}
The annotation mappedBy ideally should always be used in the Parent side (Company class) of the bi directional relationship, in this case it should be in Company class pointing to the member variable 'company' of the Child class (Branch class)
The annotation #JoinColumn is used to specify a mapped column for joining an entity association, this annotation can be used in any class (Parent or Child) but it should ideally be used only in one side (either in parent class or in Child class not in both) here in this case i used it in the Child side (Branch class) of the bi directional relationship indicating the foreign key in the Branch class.
below is the working example :
parent class , Company
#Entity
public class Company {
private int companyId;
private String companyName;
private List<Branch> branches;
#Id
#GeneratedValue
#Column(name="COMPANY_ID")
public int getCompanyId() {
return companyId;
}
public void setCompanyId(int companyId) {
this.companyId = companyId;
}
#Column(name="COMPANY_NAME")
public String getCompanyName() {
return companyName;
}
public void setCompanyName(String companyName) {
this.companyName = companyName;
}
#OneToMany(fetch=FetchType.LAZY,cascade=CascadeType.ALL,mappedBy="company")
public List<Branch> getBranches() {
return branches;
}
public void setBranches(List<Branch> branches) {
this.branches = branches;
}
}
child class, Branch
#Entity
public class Branch {
private int branchId;
private String branchName;
private Company company;
#Id
#GeneratedValue
#Column(name="BRANCH_ID")
public int getBranchId() {
return branchId;
}
public void setBranchId(int branchId) {
this.branchId = branchId;
}
#Column(name="BRANCH_NAME")
public String getBranchName() {
return branchName;
}
public void setBranchName(String branchName) {
this.branchName = branchName;
}
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="COMPANY_ID")
public Company getCompany() {
return company;
}
public void setCompany(Company company) {
this.company = company;
}
}
I'd just like to add that #JoinColumn does not always have to be related to the physical information location as this answer suggests. You can combine #JoinColumn with #OneToMany even if the parent table has no table data pointing to the child table.
How to define unidirectional OneToMany relationship in JPA
Unidirectional OneToMany, No Inverse ManyToOne, No Join Table
It seems to only be available in JPA 2.x+ though. It's useful for situations where you want the child class to just contain the ID of the parent, not a full on reference.
Let me make it simple.
You can use #JoinColumn on either sides irrespective of mapping.
Let's divide this into three cases.
1) Uni-directional mapping from Branch to Company.
2) Bi-direction mapping from Company to Branch.
3) Only Uni-directional mapping from Company to Branch.
So any use-case will fall under this three categories. So let me explain how to use #JoinColumn and mappedBy.
1) Uni-directional mapping from Branch to Company.
Use JoinColumn in Branch table.
2) Bi-direction mapping from Company to Branch.
Use mappedBy in Company table as describe by #Mykhaylo Adamovych's answer.
3)Uni-directional mapping from Company to Branch.
Just use #JoinColumn in Company table.
#Entity
public class Company {
#OneToMany(cascade = CascadeType.ALL , fetch = FetchType.LAZY)
#JoinColumn(name="courseId")
private List<Branch> branches;
...
}
This says that in based on the foreign key "courseId" mapping in branches table, get me list of all branches. NOTE: you can't fetch company from branch in this case, only uni-directional mapping exist from company to branch.
JPA is a layered API, the different levels have their own annotations. The highest level is the (1) Entity level which describes persistent classes then you have the (2) relational database level which assume the entities are mapped to a relational database and (3) the java model.
Level 1 annotations: #Entity, #Id, #OneToOne, #OneToMany, #ManyToOne, #ManyToMany.
You can introduce persistency in your application using these high level annotations alone. But then you have to create your database according to the assumptions JPA makes. These annotations specify the entity/relationship model.
Level 2 annotations: #Table, #Column, #JoinColumn, ...
Influence the mapping from entities/properties to the relational database tables/columns if you are not satisfied with JPA's defaults or if you need to map to an existing database. These annotations can be seen as implementation annotations, they specify how the mapping should be done.
In my opinion it is best to stick as much as possible to the high level annotations and then introduce the lower level annotations as needed.
To answer the questions: the #OneToMany/mappedBy is nicest because it only uses the annotations from the entity domain. The #oneToMany/#JoinColumn is also fine but it uses an implementation annotation where this is not strictly necessary.
#Entity
public class Company {
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinColumn(name = "company_id_ref", referencedColumnName = "company_id")
private List<Branch> branches;
...
}
That Will give below Hibernate logs
Hibernate: select nextval ('hibernate_sequence')
Hibernate: select nextval ('hibernate_sequence')
Hibernate: insert into company (name, company_id) values (?, ?)
Hibernate: insert into branch (company_id_ref, name, id) values (?, ?, ?)
Hibernate: update branch set company_id_ref=? where id=?
And
#Entity
public class Company {
#OneToMany(cascade = CascadeType.ALL , fetch = FetchType.LAZY,
mappedBy = "company")
private List<Branch> branches;
...
}
That will give below Hibernate logs
Hibernate: select nextval ('hibernate_sequence')
Hibernate: select nextval ('hibernate_sequence')
Hibernate: insert into company (name, company_id) values (?, ?)
Hibernate: insert into branch (company_id_ref, name, id) values (?, ?, ?)
We can clearly see that #joinColumn will cause additional update queries.
so you do not need to set parent entity explicitly to child entity,
That we have to do while using mappedBy
to save children with a parent
I know for a fact that with clause on fetch join are not allowed by hibernate
I am using spring data jpa and postgres.
Here is how my entity is designed
public class Organisation {
#Id
private Long id;
#OneToMany(mappedBy = "organisation", cascade = CascadeType.ALL)
#LazyCollection(LazyCollectionOption.EXTRA)
private Set<Assignment> assignments = new HashSet<>();
#OneToMany(mappedBy = "organisation", cascade = CascadeType.ALL)
private List<Event> events;
}
public class Event {
#Id
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "organisations_id", nullable = false)
private Organisation organisation;
#OneToMany(mappedBy = "event", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private Set<EventValue> eventValues = new HashSet<>();
}
public class EventValue {
#Id
private Long id;
#ManyToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "event_id")
private Event Event;
#ManyToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "assignment_id")
private Assignment assignment;
}
public class Assignment {
#Id
private Long id;
#OneToMany(mappedBy = "assignment", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private Set<EventValue> eventValues = new HashSet<>();
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "organisation_id", nullable = false)
private Organisation organisation;
}
Kind of a three way mapping. What the above entity design says is:
one organisation can have many events
one events can have many event values
one organisation can have many assignments
one assignment can be mapped to only one organisation and whithin the event of this organisation it is supposed to have only one event value (but as per entity design above it can have set of values which is not directly mapped to assignment)
So, I tried to query something like this.
#Query("select assignment from Assignment left join fetch assignment.organisation org
left join fetch org.event event left join fetch event.eventValues eventValue
with eventValue.assignment.id=?1 where assignment.id=?1)
Assignment getByAssignmentId(Long id);
What am I trying to achive with the query ?
To get assignment with given (id) -> organisation -> list of activities with HashSet containing only ONE activity value mapped to assignment.
The query is obviously going to fail because of using with clause on fetch join. I somehow feel the entity has 3 way dependency so it might be wrong.
I do not want to generic jdbcTemplate solution or SqlResultMapping solution where we need to do some kind of projection and set values manually. Is there a ORM solution to solve this problem ?
The reason why a WITH or ON clause is disallowed for join fetches is pretty simple. Hibernate works on managed entities, which means, once the entities are managed by the current persistence context, changes done to these objects will be flushed back to the database at the end of the transaction.
Now, if you were allowed to use the WITH or ON clause in a join fetch, the querying itself could alter the managed state of a collection, which would lead to UPDATE/DELETE statements to flush the collection changes back. Since this is completely unexpected, but a necessary side effect, it is disallowed.
Having said that, this is a perfect use case for Blaze-Persistence Entity Views.
Blaze-Persistence is a query builder on top of JPA which supports many of the advanced DBMS features on top of the JPA model. I created Entity Views on top of it to allow easy mapping between JPA models and custom interface defined models, something like Spring Data Projections on steroids. The idea is that you define your target structure the way you like and map attributes(getters) via JPQL expressions to the entity model. Since the attribute name is used as default mapping, you mostly don't need explicit mappings as 80% of the use cases is to have DTOs that are a subset of the entity model.
A DTO mapping for your model could look as simple as the following
#EntityView(Assignment.class)
interface AssignmentDto {
Long getId();
OrganisationDto getOrganisation();
}
#EntityView(Organisation.class)
interface OrganisationDto {
Long getId();
List<EventDto> getEvents();
}
#EntityView(Event.class)
interface EventDto {
Long getId();
#Mapping("eventValues[assignment.id = VIEW_ROOT(id)]")
EventValueDto getEventValue();
}
#EntityView(EventValue.class)
interface EventValueDto {
Long getId();
// Other stuff
}
The JOIN condition is modeled in the mapping expression eventValues[assignment.id = VIEW_ROOT(id)] which translates to what you would expect.
Querying is a matter of applying the entity view to a query, the simplest being just a query by id.
AssignmentDto dto = entityViewManager.find(entityManager, AssignmentDto.class, id);
But 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
It will only fetch the mappings that you tell it to fetch.
Currently working on a project where we want to extract with Hibernate the following datamodel (model is a little bit simplified). We have a class A which contains some optional data which is stored in class B
#Entity
#Data
#Table(name = "A")
public class Country {
#Id
private UUID id;
private String someCommon;
#PrimaryKeyJoinColumn
#OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private B details;
}
#Entity
#Data
#Table(name = "B")
public class B {
#Id
private UUID id;
private String someDetail;
}
Fetching data works fine, except that when class B is not found for some instance of A, Hibernate does an extra query for that specific instance to retrieve the details of A. I.e in the logs these are the queries executed:
select a0_.id as id1_0_0_, b1_.id as id1_1_1_, a0_.some_common as some_common2_0_0_, b1_.some_detail as some_detail_2_1_1_ from a a0_ left outer join b b1_ on a0_.id=b1_.id
select b0_.id as id1_1_0_, b0_.some_detail as some_detail_2_1_0_ from b b0_ where b0_.id=?
Where in the second query the id is set to the id of the instance which does not have details.
So it looks like Hibernate is not supporting optional OneToOne relationships in an efficient manner. Any ideas on how to force Hibernate not doing the second query but just accepting the details are null?
There is no way to get rid of second query as you mentioned in hibernate because If the association is optional, Hibernate has no way to know if an address exists for a given person without issuing a query. so closest thing you can do is to call for second query only when its intended:
So as to avoid second query you have to opt for Lazy Loading:
To do that change your mapping to set optional to false and lazy loading will be on on details:
#OneToOne(cascade = CascadeType.ALL, optional = false, fetch = FetchType.LAZY)
private B details;
Lazy loading makes sure details will be fetched only when its intended.
I have the entity User:
#Entity
#Table(name = "users")
public class User {
(...)
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(name = "users_roles",
joinColumns = #JoinColumn(name = "user_id", nullable = false),
inverseJoinColumns = #JoinColumn(name = "role_id", nullable = false)
)
private List<Role> roles;
}
and entity Role with simple id and name columns.
User and Role have many-to-many relation with join table users_roles.
I have created method to remove a user:
public void remove(long userId) {
Session session = getSession();
//NativeQuery joinTableQuery = session.createNativeQuery("DELETE FROM users_roles ur WHERE ur.user_id = :userId");
//joinTableQuery.setParameter("userId", userId);
//joinTableQuery.executeUpdate();
Query userQuery = session.createQuery("DELETE FROM User u WHERE u.id = :userId");
userQuery.setParameter("userId", userId);
userQuery.executeUpdate();
}
I have commented out first NativeQuery on purpose to check what happens. And what is interesting now Hibernate generates two queries:
Hibernate: delete from users_roles where (user_id) in (select id from users where id=?)
Hibernate: delete from users where id=?
Question:
Why does Hibernate generate additional query on users_roles (join table) while my User entity has no CascadeType.REMOVE set on #ManyToMany relation? I thought I have to write it myself (commented part).
Your User entity owns the many-to-many association to the Role entity. When you remove a User, Hibernate automatically also removes all entries from the association table. But it doesn't cascade the remove operation to the Role entity.
You should never use CascadeType.REMOVE on a many-to-many association. If you remove an entity, Hibernate will remove all associated entities even if they are still referenced by other entities. I explained that in great detail on my blog.
If you would use CascadeType.REMOVE on your roles association and remove a User, Hibernate would remove all Role entities referenced by that User. It would do that even if there are other User entity objects that are associated with these Roles.
I'm starting my first project with Hibernate 4.2.21 and first with JPA 2.0, I want to create a relationship OneToMany Unidirectional. I saw a lot examples in version of Hibernate 3 but not much in 4.2.21 This example works perfectly but I don't know if is a good practice, I want to know the Opinion from another members about that?
Relationship One To Many:
-Parent Template:
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name = "template_id")
private Set<Variable> variables = new LinkedHashSet<Variable>();
-Child: Variable
#Column(name = "template_id", nullable = false)
Integer templateId;
According with this another post's.
Hibernate unidirectional one to many association - why is a join table better?
http://docs.jboss.org/hibernate/stable/annotations/reference/en/html_single/#entity-mapping-association-collections
A unidirectional one to many using a foreign key column in the owned entity is not that common and not really recommended. We strongly advise you to use a join table for this kind of association (as explained in the next section). This kind of association is described through a #JoinColumn
#Entity
public class Customer implements Serializable {
#OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
#JoinColumn(name="CUST_ID")
public Set<Ticket> getTickets() {
...
}
#Entity
public class Ticket implements Serializable {
... //no bidir
}
Unidirectional with join table
A unidirectional one to many with join table is much preferred. This association is described through an #JoinTable.
#Entity
public class Trainer {
#OneToMany
#JoinTable(
name="TrainedMonkeys",
joinColumns = #JoinColumn( name="trainer_id"),
inverseJoinColumns = #JoinColumn( name="monkey_id")
)
public Set<Monkey> getTrainedMonkeys() {
...
}
#Entity
public class Monkey {
... //no bidir
}
Finally the only way it's implement the bidirectional method... yes or no?