Hibernate & JPA “mappedBy” vs. owner of the relation & cascadesWhat are the possible values of the Hibernate hbm2ddl.auto configuration and what do they doJPA (hibernate) onetomany relationWhat are the options for storing hierarchical data in a relational database?One to many mappedByWhat's the difference between JPA and Hibernate?What's the difference between @JoinColumn and mappedBy when using a JPA @OneToMany associationJPA Bidirectional Relationshipbiderectional many to many annotation hibernate mappedbyJPA OneToMany persist with CascadeType.ALL doesn't persist childUnidirectional OneToOne with joincolumn in target entity
Lead Amalgam as a Material for a Sword
How to influence manager to not schedule team meetings during lunch?
Why are there two bearded faces wearing red hats on my stealth bomber icon?
I feel like most of my characters are the same, what can I do?
What did the controller say during my approach to land (audio clip)?
Does battery condition have anything to do with macbook pro performance?
I reverse the source code, you negate the output!
Removing rows containing NA in every column
How often is duct tape used during crewed space missions?
Simulate a 1D Game-of-Life-ish Model
Make Interviewee Comfortable in Potentially Intimate Environment
Wired to Wireless Doorbell
Minimize taxes now that I earn more
How does one calculate the distribution of the Matt Colville way of rolling stats?
Why do things cool down?
As an employer, can I compel my employees to vote?
How do I improve in sight reading?
Why are Fuji lenses more expensive than others?
Delete empty subfolders, keep parent folder
Find all files in directories named foo
How do I write this symbol in latex? (disjoint sharp operator)
What is the word for a person who destroys monuments?
How should errors be reported in scientific libraries?
Integrability of log of distance function
Hibernate & JPA “mappedBy” vs. owner of the relation & cascades
What are the possible values of the Hibernate hbm2ddl.auto configuration and what do they doJPA (hibernate) onetomany relationWhat are the options for storing hierarchical data in a relational database?One to many mappedByWhat's the difference between JPA and Hibernate?What's the difference between @JoinColumn and mappedBy when using a JPA @OneToMany associationJPA Bidirectional Relationshipbiderectional many to many annotation hibernate mappedbyJPA OneToMany persist with CascadeType.ALL doesn't persist childUnidirectional OneToOne with joincolumn in target entity
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;
Background
Suppose we have bidirectional OneToOne
relationship.
There are User
and Address
entity. User
has many Address
es.
CREATE SEQUENCE IF NOT EXISTS hibernate_sequence;
CREATE TABLE users (
id BIGINT PRIMARY KEY
);
CREATE TABLE addresses (
id BIGINT PRIMARY KEY,
user_id BIGINT NOT NULL UNIQUE CONSTRAINT fk_addresses_user_id REFERENCES users(id) ON DELETE CASCADE,
);
and
@Table(name = "users")
public class User
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
//mappings
private Address address;
@Table(name = "addresses")
public class Address
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
//mapings
private User user;
Disclaimer:
I'm using OneToOne
as an example but the question is about relations in general so the right approach is valid for ManyToMany
as well.
TL;DR - the question is about using mappedBy<->relation owner<->cascades<->managing other side in setters
in general
Questions:
- In database there should be user_id in address table table, right? Who is the owner of the relation then?
- In entities: which one should have mappedBy - (
User
orAddress
) / (Owner or Inverse)?- This link: https://coderanch.com/t/595728/databases/Newbie-Hibernate-OneToMany-owning-side states: "Note that the mappedBy automatically makes the relationship the inverse or non-owning side." so
Address
should have mappedBy - While in this link: https://vladmihalcea.com/the-best-way-to-map-a-onetoone-relationship-with-jpa-and-hibernate/
Post
(User
in my example) have mappedBy toPostDetails
(Address
in my example) - Javadoc: https://docs.oracle.com/javaee/7/api/javax/persistence/OneToOne.html#mappedBy() says "The field that owns the relationship" so
User
owns the relation, and thereforeAddress
should have mappedBy (CustomerRecord
in JavaDoc) - But hibernate documentation: http://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html#associations-one-to-one-bidirectional the parent
Phone
(Person
in my example) has mappedBy toPhoneDetails
(Address
)
- This link: https://coderanch.com/t/595728/databases/Newbie-Hibernate-OneToMany-owning-side states: "Note that the mappedBy automatically makes the relationship the inverse or non-owning side." so
- On which side (
User
orAddress
) / (mappedBy or inverse-side) the@OneToOne(cascade = CascadeType.MERGE, CascadeType.DETACH, CascadeType.REFRESH)
should be placed? - And last question: which of the entities should manage the relation like this:
public void addAddress(Address address)
if (address != null)
address.addUser(this);
this.addresses.add(address);
public void removeAddress(Address address)
if (address != null)
address.removeUser(this);
this.addresses.remove(address);
public Set<Address> getAddresses()
return Collections.unmodifiableSet(this.addresses);
the (User
or Address
) / (mappedBy or inverse-side)?
- This link: https://vladmihalcea.com/the-best-way-to-map-a-onetomany-association-with-jpa-and-hibernate/ shows the approach listed above (where the parent,
User
in my example, manages the relation) - But here: https://www.quora.com/What-is-the-purpose-of-mapped-by-element-in-OneToMany-annotation-in-Hibernate Vlad says: "it’s always good practice if the child side, where the Foreign Key is located, controls the association", so the Address should "controll the relation" (exactly the opposite)?
Moreover - look at theese two links:
https://docs.oracle.com/javaee/7/api/javax/persistence/OneToOne.html - here CustomerRecord has mappedBy
https://docs.oracle.com/javaee/7/api/javax/persistence/OneToMany.html - but here Customer has mappedBy!
Thank you in advance
PS. Previous version of my question was using OneToMany
as an example, but because inverse - ManyToOne
does not have mapped by I changed it to OneToOne
which better shows the problem
java sql hibernate
add a comment
|
Background
Suppose we have bidirectional OneToOne
relationship.
There are User
and Address
entity. User
has many Address
es.
CREATE SEQUENCE IF NOT EXISTS hibernate_sequence;
CREATE TABLE users (
id BIGINT PRIMARY KEY
);
CREATE TABLE addresses (
id BIGINT PRIMARY KEY,
user_id BIGINT NOT NULL UNIQUE CONSTRAINT fk_addresses_user_id REFERENCES users(id) ON DELETE CASCADE,
);
and
@Table(name = "users")
public class User
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
//mappings
private Address address;
@Table(name = "addresses")
public class Address
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
//mapings
private User user;
Disclaimer:
I'm using OneToOne
as an example but the question is about relations in general so the right approach is valid for ManyToMany
as well.
TL;DR - the question is about using mappedBy<->relation owner<->cascades<->managing other side in setters
in general
Questions:
- In database there should be user_id in address table table, right? Who is the owner of the relation then?
- In entities: which one should have mappedBy - (
User
orAddress
) / (Owner or Inverse)?- This link: https://coderanch.com/t/595728/databases/Newbie-Hibernate-OneToMany-owning-side states: "Note that the mappedBy automatically makes the relationship the inverse or non-owning side." so
Address
should have mappedBy - While in this link: https://vladmihalcea.com/the-best-way-to-map-a-onetoone-relationship-with-jpa-and-hibernate/
Post
(User
in my example) have mappedBy toPostDetails
(Address
in my example) - Javadoc: https://docs.oracle.com/javaee/7/api/javax/persistence/OneToOne.html#mappedBy() says "The field that owns the relationship" so
User
owns the relation, and thereforeAddress
should have mappedBy (CustomerRecord
in JavaDoc) - But hibernate documentation: http://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html#associations-one-to-one-bidirectional the parent
Phone
(Person
in my example) has mappedBy toPhoneDetails
(Address
)
- This link: https://coderanch.com/t/595728/databases/Newbie-Hibernate-OneToMany-owning-side states: "Note that the mappedBy automatically makes the relationship the inverse or non-owning side." so
- On which side (
User
orAddress
) / (mappedBy or inverse-side) the@OneToOne(cascade = CascadeType.MERGE, CascadeType.DETACH, CascadeType.REFRESH)
should be placed? - And last question: which of the entities should manage the relation like this:
public void addAddress(Address address)
if (address != null)
address.addUser(this);
this.addresses.add(address);
public void removeAddress(Address address)
if (address != null)
address.removeUser(this);
this.addresses.remove(address);
public Set<Address> getAddresses()
return Collections.unmodifiableSet(this.addresses);
the (User
or Address
) / (mappedBy or inverse-side)?
- This link: https://vladmihalcea.com/the-best-way-to-map-a-onetomany-association-with-jpa-and-hibernate/ shows the approach listed above (where the parent,
User
in my example, manages the relation) - But here: https://www.quora.com/What-is-the-purpose-of-mapped-by-element-in-OneToMany-annotation-in-Hibernate Vlad says: "it’s always good practice if the child side, where the Foreign Key is located, controls the association", so the Address should "controll the relation" (exactly the opposite)?
Moreover - look at theese two links:
https://docs.oracle.com/javaee/7/api/javax/persistence/OneToOne.html - here CustomerRecord has mappedBy
https://docs.oracle.com/javaee/7/api/javax/persistence/OneToMany.html - but here Customer has mappedBy!
Thank you in advance
PS. Previous version of my question was using OneToMany
as an example, but because inverse - ManyToOne
does not have mapped by I changed it to OneToOne
which better shows the problem
java sql hibernate
add a comment
|
Background
Suppose we have bidirectional OneToOne
relationship.
There are User
and Address
entity. User
has many Address
es.
CREATE SEQUENCE IF NOT EXISTS hibernate_sequence;
CREATE TABLE users (
id BIGINT PRIMARY KEY
);
CREATE TABLE addresses (
id BIGINT PRIMARY KEY,
user_id BIGINT NOT NULL UNIQUE CONSTRAINT fk_addresses_user_id REFERENCES users(id) ON DELETE CASCADE,
);
and
@Table(name = "users")
public class User
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
//mappings
private Address address;
@Table(name = "addresses")
public class Address
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
//mapings
private User user;
Disclaimer:
I'm using OneToOne
as an example but the question is about relations in general so the right approach is valid for ManyToMany
as well.
TL;DR - the question is about using mappedBy<->relation owner<->cascades<->managing other side in setters
in general
Questions:
- In database there should be user_id in address table table, right? Who is the owner of the relation then?
- In entities: which one should have mappedBy - (
User
orAddress
) / (Owner or Inverse)?- This link: https://coderanch.com/t/595728/databases/Newbie-Hibernate-OneToMany-owning-side states: "Note that the mappedBy automatically makes the relationship the inverse or non-owning side." so
Address
should have mappedBy - While in this link: https://vladmihalcea.com/the-best-way-to-map-a-onetoone-relationship-with-jpa-and-hibernate/
Post
(User
in my example) have mappedBy toPostDetails
(Address
in my example) - Javadoc: https://docs.oracle.com/javaee/7/api/javax/persistence/OneToOne.html#mappedBy() says "The field that owns the relationship" so
User
owns the relation, and thereforeAddress
should have mappedBy (CustomerRecord
in JavaDoc) - But hibernate documentation: http://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html#associations-one-to-one-bidirectional the parent
Phone
(Person
in my example) has mappedBy toPhoneDetails
(Address
)
- This link: https://coderanch.com/t/595728/databases/Newbie-Hibernate-OneToMany-owning-side states: "Note that the mappedBy automatically makes the relationship the inverse or non-owning side." so
- On which side (
User
orAddress
) / (mappedBy or inverse-side) the@OneToOne(cascade = CascadeType.MERGE, CascadeType.DETACH, CascadeType.REFRESH)
should be placed? - And last question: which of the entities should manage the relation like this:
public void addAddress(Address address)
if (address != null)
address.addUser(this);
this.addresses.add(address);
public void removeAddress(Address address)
if (address != null)
address.removeUser(this);
this.addresses.remove(address);
public Set<Address> getAddresses()
return Collections.unmodifiableSet(this.addresses);
the (User
or Address
) / (mappedBy or inverse-side)?
- This link: https://vladmihalcea.com/the-best-way-to-map-a-onetomany-association-with-jpa-and-hibernate/ shows the approach listed above (where the parent,
User
in my example, manages the relation) - But here: https://www.quora.com/What-is-the-purpose-of-mapped-by-element-in-OneToMany-annotation-in-Hibernate Vlad says: "it’s always good practice if the child side, where the Foreign Key is located, controls the association", so the Address should "controll the relation" (exactly the opposite)?
Moreover - look at theese two links:
https://docs.oracle.com/javaee/7/api/javax/persistence/OneToOne.html - here CustomerRecord has mappedBy
https://docs.oracle.com/javaee/7/api/javax/persistence/OneToMany.html - but here Customer has mappedBy!
Thank you in advance
PS. Previous version of my question was using OneToMany
as an example, but because inverse - ManyToOne
does not have mapped by I changed it to OneToOne
which better shows the problem
java sql hibernate
Background
Suppose we have bidirectional OneToOne
relationship.
There are User
and Address
entity. User
has many Address
es.
CREATE SEQUENCE IF NOT EXISTS hibernate_sequence;
CREATE TABLE users (
id BIGINT PRIMARY KEY
);
CREATE TABLE addresses (
id BIGINT PRIMARY KEY,
user_id BIGINT NOT NULL UNIQUE CONSTRAINT fk_addresses_user_id REFERENCES users(id) ON DELETE CASCADE,
);
and
@Table(name = "users")
public class User
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
//mappings
private Address address;
@Table(name = "addresses")
public class Address
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
//mapings
private User user;
Disclaimer:
I'm using OneToOne
as an example but the question is about relations in general so the right approach is valid for ManyToMany
as well.
TL;DR - the question is about using mappedBy<->relation owner<->cascades<->managing other side in setters
in general
Questions:
- In database there should be user_id in address table table, right? Who is the owner of the relation then?
- In entities: which one should have mappedBy - (
User
orAddress
) / (Owner or Inverse)?- This link: https://coderanch.com/t/595728/databases/Newbie-Hibernate-OneToMany-owning-side states: "Note that the mappedBy automatically makes the relationship the inverse or non-owning side." so
Address
should have mappedBy - While in this link: https://vladmihalcea.com/the-best-way-to-map-a-onetoone-relationship-with-jpa-and-hibernate/
Post
(User
in my example) have mappedBy toPostDetails
(Address
in my example) - Javadoc: https://docs.oracle.com/javaee/7/api/javax/persistence/OneToOne.html#mappedBy() says "The field that owns the relationship" so
User
owns the relation, and thereforeAddress
should have mappedBy (CustomerRecord
in JavaDoc) - But hibernate documentation: http://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html#associations-one-to-one-bidirectional the parent
Phone
(Person
in my example) has mappedBy toPhoneDetails
(Address
)
- This link: https://coderanch.com/t/595728/databases/Newbie-Hibernate-OneToMany-owning-side states: "Note that the mappedBy automatically makes the relationship the inverse or non-owning side." so
- On which side (
User
orAddress
) / (mappedBy or inverse-side) the@OneToOne(cascade = CascadeType.MERGE, CascadeType.DETACH, CascadeType.REFRESH)
should be placed? - And last question: which of the entities should manage the relation like this:
public void addAddress(Address address)
if (address != null)
address.addUser(this);
this.addresses.add(address);
public void removeAddress(Address address)
if (address != null)
address.removeUser(this);
this.addresses.remove(address);
public Set<Address> getAddresses()
return Collections.unmodifiableSet(this.addresses);
the (User
or Address
) / (mappedBy or inverse-side)?
- This link: https://vladmihalcea.com/the-best-way-to-map-a-onetomany-association-with-jpa-and-hibernate/ shows the approach listed above (where the parent,
User
in my example, manages the relation) - But here: https://www.quora.com/What-is-the-purpose-of-mapped-by-element-in-OneToMany-annotation-in-Hibernate Vlad says: "it’s always good practice if the child side, where the Foreign Key is located, controls the association", so the Address should "controll the relation" (exactly the opposite)?
Moreover - look at theese two links:
https://docs.oracle.com/javaee/7/api/javax/persistence/OneToOne.html - here CustomerRecord has mappedBy
https://docs.oracle.com/javaee/7/api/javax/persistence/OneToMany.html - but here Customer has mappedBy!
Thank you in advance
PS. Previous version of my question was using OneToMany
as an example, but because inverse - ManyToOne
does not have mapped by I changed it to OneToOne
which better shows the problem
java sql hibernate
java sql hibernate
edited Mar 28 at 15:30
Kamil
asked Mar 28 at 14:31
KamilKamil
85 bronze badges
85 bronze badges
add a comment
|
add a comment
|
3 Answers
3
active
oldest
votes
The mappedBy
attribute marks the side of a bidirectional association which does not own the association. Usually, that's the side which does not have the Foreign Key.
On the other hand, cascading entity state transitions only makes sense from parents to child entities. Doing the cascade from the child entity where the FK is stored is a code smell.
It's as simple as that.
Vlad, Let's say this is article 1 and this is article 2 In article 1Post
hasmappedBy
toPostDetails
while in article 2Tag
has mappedBy toPost
. Article 2 seems to be correct while Article 1 seems to be incorrect. Am I wrong? If yes - could you point me to the article (or chapter of your book) that explains why?
– Kamil
Mar 28 at 16:07
Moreover: in article 1 entity that hasmappedBy
is managing the relation (setDetails
) while in article 2 entity that doesn't havemappedBy
is managing the relation (addTag
/removeTag
) are both approaches valid?
– Kamil
Mar 28 at 16:10
Both articles are correct. You are comparing a one-to-one association to a many-to-many one, hence your confusion. A many to many association is between 2 parents while the one-to-one is a parent-child one. MappedBy is just a flag marking the source of truth in a bidirectional association. That's it and it has nothing to do with cascading.
– Vlad Mihalcea
Mar 28 at 16:32
So what you're saying is: a) The "Owner" of the relation is the entity which table containt ForeignKey b) The "Parent" of the relation is up to the business c) "Parent" and "Owner" are completly orthogonal and unrelated to each other, Hence: 1) I can have cascades on both "mappedBy" and inverse side? and 2) cascades are related to "Parent" and 3) cascases are not related to "Owner" of the relation (mappedBy)? Am I 100% Correct?
– Kamil
Mar 28 at 16:48
No, that's not what I said.
– Vlad Mihalcea
Mar 28 at 16:56
|
show 4 more comments
- In database there should be user_id in address table table, right? Who is the owner of the relation then?
- Exactly. Basically, the owner is address, as it's the owner who holds the reference.
- In entities: which one should have mappedBy - User or Address?
@ManyToOne
doesn't even have the attribute mappedBy. It's present only on xToMany annotations.
Your mapping should be:
@Table(name = "users")
public class User
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
@OneToMany(mappedBy="user", cascade = ...) // atenttion, this refer the attribute name as opposed to the column name
private Set<Address> addresses = new HashSet<>();
@Table(name = "addresses")
public class Address
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
@ManyToOne
@JoinColumn(name="user_id") // the name is optional if you refer to the PK
private User user;
On which side (User or Address?) the @ManyToMany(cascade = CascadeType.MERGE, CascadeType.DETACH, CascadeType.REFRESH) should be placed?
And last question: which of the entities should manage the relation like this:
In this case, you want to handle User, and then JPA handles Address automatically.
Therefore, the cascade would be on User.
On this side (OneToMany), you probably also want to add orphanRemoval = true
.
Trying to adjust after clarification...
About the support, JPA supports cascading from both sides, ok?!
From where you should use it depends on your domain.
You are supposed to use it on the Entity which you use on entityManager operations, for instance: em.persist(user)
or em.merge(address)
.
Really, depends on how your code is.
In this specify case, it seems it makes more sense to leave on User. I suppose you have an User CRUD, which also includes address.
In this case, it makes sense when you create or remove an User, then its addresses are created/remove together.
On the other side, it wouldn't make sense to cascade from the Address. If you remove an Address, it does NOT mean that the user should be removed too.
Can you see?! You need to check your use case. The side to use it (whether oneToMany or manyToOne or ...) should be thought and decided based on your needs on that moment.
thank you for your answer. Two questions: 1) Are you sure that the side with mappedBy whould manage cascades? 2) Which of the class should set the opposite in setters: User like this like in my example or Address?
– Kamil
Mar 28 at 15:00
Hey! 1. Yes, JPA is capable of handling that cascading. 2. Yeah, you also need to set the user instance on you Address, exactly the way you did onaddAddress
. I think JPA could be smarter in this point
– Ricardo Silva
Mar 28 at 15:20
1) I changed my main question because you were misleaded by OneToMany used in the example. I would apprieciate if you could read the new version of the question. 2) I'm aware that JPA can handle cascades, but the question is "On whcich side cascade should happed" - where mappedBy is or the inverse? There are sources that say exactly the opposite 3) Also the question is not if I should set instance but "On which side" - mappedBy is or the inverse?
– Kamil
Mar 28 at 15:33
OK. I changed it. I hope it's a little clearer now
– Ricardo Silva
Mar 28 at 16:04
Thak you for your help
– Kamil
Mar 28 at 16:54
add a comment
|
This is what I have learnt so far.
If I'm mistaken to any of the points - please let me know in comments, and I edit the answer.
Database
Owner of the relation
`According to this answer
Basically, the owner is address, as it's the owner who holds the reference.
So the "owner
" of relation in database is entity with foreign key - Address
in case of OneToOne/OneToMany.
Moreover - it seems that in the same time "owner
" of the database relation is the Child
in Hibernate relation - but I need confirmation for this
OneToOne
Parent/Child
According to this article
The Post entity is the parent, while the PostDetails is the child association because the Foreign Key is located in the post_details database table
So User
is the Parent
and Address
is the Child
here (because Address
holds foreign key)
mappedBy
According to this answer
The mappedBy attribute marks the side of a bidirectional association which does not own the association. Usually, that's the side which does not have the Foreign Key.
So mappedBy
should be placed in User
, because foreign key
is in Address
.
In seems that in @OneToOne
mappedBy
should be always placed in Parent
(entity not holding the foreign key)
JoinColumn
It seems that JoinColumn
in OneToOne
must be always placed in Child
(since it holds foreign key)
Cascades
According to this answer
cascading entity state transitions only makes sense from parents to child entities.
So cascades
in OneToOne
should be always done in Parent
, so - according to previous links - User
in this example
set utility method
I'm not sure but it seems that utility setter should be placed in User
.
Is it always placed in the Parent
?
Outcome
CREATE SEQUENCE IF NOT EXISTS hibernate_sequence;
CREATE TABLE users (
id BIGINT PRIMARY KEY
);
CREATE TABLE addresses (
id BIGINT PRIMARY KEY,
user_id BIGINT NOT NULL UNIQUE CONSTRAINT fk_addresses_user_id REFERENCES users(id) ON DELETE CASCADE,
);
@Table(name = "users")
public class User
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
@OneToOne(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY, optional = false, orphanRemoval = true)
private Address address;
public void setAddress(Address address)
if (address != null)
address.setUser(this);
this.address = address;
@Table(name = "addresses")
public class Address
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User user;
OneToMany
Parent/Child
It seems to be the same as with OneToOne
, so User
is the Parent
and Address
is the Child
(because it has foreign key), but I'm not 100% sure...
mappedBy
In this article mappedBy
is placed in Parent
(but I'm not sure if this is the rule of thumb though)
JoinColumn
It seems that JoinColumn
in OneToMany
must be always placed in Child
(since it holds foreign key)
Cascades
In above article cascades
are also placed in Parent
(but I'm not sure if this is the rule of thumb as well)
add/remove utility methods
In above article utility methods
are also placed in Parent
(but I'm not sure if this is the rule of thumb as well)
Outcome
CREATE SEQUENCE IF NOT EXISTS hibernate_sequence;
CREATE TABLE users (
id BIGINT PRIMARY KEY
);
CREATE TABLE addresses (
id BIGINT PRIMARY KEY,
user_id BIGINT NOT NULL CONSTRAINT fk_addresses_user_id REFERENCES users(id) ON DELETE CASCADE,
);
@Table(name = "users")
public class User
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
private List<Address> addresses = new ArrayList<>();
public void addAddress(Address address)
if (address != null)
address.setUser(this);
this.addresses.add(address);
public void removeAddress(Address address)
this.addresses.remove(address);
if (address != null)
address.setUser(null);
public Set<Address> getAddresses()
return Collections.unmodifiableSet(this.addresses);
@Table(name = "addresses")
public class Address
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User user;
ManyToMany
Parent/Child
According to this article
A typical many-to-many database association includes two parent tables
So both User
and Address
are Parents
mappedBy
In the same article Vlad wrote:
The mappedBy attribute of the posts association in the Tag entity marks that, in this bidirectional relationship, the Post entity own the association
Therefore here is the eception, because we don't have one Parent
.
It is not clear to me what Vlad means exactly by "own", but if User
"owns" the relation, mappedBy
must be placed in Address
,
JoinTable
It seems that JoinTable
must be always placed in entity that "owns" the relation, so User
in this case.
Am I right?
Cascades
According to the same article cascades
should be always placed in "owner" defined above, so User
in this case.
Also important thing to notice is that we can not use REMOVE
cascade
add/remove utility methods
It seems that add/remove utility methods
should be placed in User
.
Is this the rule of thumb, that utility methods
should be alway placed in entity that "owns" the relation?
Outcome
CREATE SEQUENCE IF NOT EXISTS hibernate_sequence;
CREATE TABLE users (
id BIGINT PRIMARY KEY
);
CREATE TABLE addresses (
id BIGINT PRIMARY KEY,
);
CREATE TABLE users_addresses (
user_id BIGINT NOT NULL CONSTRAINT fk_users_addresses_user_id REFERENCES users(id) ON DELETE CASCADE,
address_id BIGINT NOT NULL CONSTRAINT fk_users_addresses_address_id REFERENCES addresses(id) ON DELETE CASCADE,
PRIMARY KEY(user_id,address_id)
);
@Table(name = "users")
public class User
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
@ManyToMany(cascade =
CascadeType.PERSIST,
CascadeType.MERGE
)
@JoinTable(name = "post_tag",
joinColumns = @JoinColumn(name = "post_id"),
inverseJoinColumns = @JoinColumn(name = "tag_id")
)
private List<Address> addresses = new ArrayList<>();
public void addAddress(Address address)
addresses.add(address);
address.getUsers().add(this);
public void removeAddress(Address address)
addresses.remove(address);
address.getUsers().remove(this);
@Table(name = "addresses")
public class Address
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
@ManyToMany(mappedBy = "addresses")
private List<User> users = new ArrayList<>();
Summary
I think this table sums it up: https://i.ibb.co/zNjZ3md/JPA-relations.png
The last thing I don't unserstand is:
- why Vlad in this article in "ManyToMany" section uses
mappedBy
inAuthor
("owner") instead ofBook
(especially that it throws exception in my code) - why in javadoc
mappedBy
is onCustomerRecord
(child) not onCustomer
(but here maybe foreign key is located in Customer, so although counter intuitive - it is correct)
add a comment
|
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/4.0/"u003ecc by-sa 4.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55400177%2fhibernate-jpa-mappedby-vs-owner-of-the-relation-cascades%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
The mappedBy
attribute marks the side of a bidirectional association which does not own the association. Usually, that's the side which does not have the Foreign Key.
On the other hand, cascading entity state transitions only makes sense from parents to child entities. Doing the cascade from the child entity where the FK is stored is a code smell.
It's as simple as that.
Vlad, Let's say this is article 1 and this is article 2 In article 1Post
hasmappedBy
toPostDetails
while in article 2Tag
has mappedBy toPost
. Article 2 seems to be correct while Article 1 seems to be incorrect. Am I wrong? If yes - could you point me to the article (or chapter of your book) that explains why?
– Kamil
Mar 28 at 16:07
Moreover: in article 1 entity that hasmappedBy
is managing the relation (setDetails
) while in article 2 entity that doesn't havemappedBy
is managing the relation (addTag
/removeTag
) are both approaches valid?
– Kamil
Mar 28 at 16:10
Both articles are correct. You are comparing a one-to-one association to a many-to-many one, hence your confusion. A many to many association is between 2 parents while the one-to-one is a parent-child one. MappedBy is just a flag marking the source of truth in a bidirectional association. That's it and it has nothing to do with cascading.
– Vlad Mihalcea
Mar 28 at 16:32
So what you're saying is: a) The "Owner" of the relation is the entity which table containt ForeignKey b) The "Parent" of the relation is up to the business c) "Parent" and "Owner" are completly orthogonal and unrelated to each other, Hence: 1) I can have cascades on both "mappedBy" and inverse side? and 2) cascades are related to "Parent" and 3) cascases are not related to "Owner" of the relation (mappedBy)? Am I 100% Correct?
– Kamil
Mar 28 at 16:48
No, that's not what I said.
– Vlad Mihalcea
Mar 28 at 16:56
|
show 4 more comments
The mappedBy
attribute marks the side of a bidirectional association which does not own the association. Usually, that's the side which does not have the Foreign Key.
On the other hand, cascading entity state transitions only makes sense from parents to child entities. Doing the cascade from the child entity where the FK is stored is a code smell.
It's as simple as that.
Vlad, Let's say this is article 1 and this is article 2 In article 1Post
hasmappedBy
toPostDetails
while in article 2Tag
has mappedBy toPost
. Article 2 seems to be correct while Article 1 seems to be incorrect. Am I wrong? If yes - could you point me to the article (or chapter of your book) that explains why?
– Kamil
Mar 28 at 16:07
Moreover: in article 1 entity that hasmappedBy
is managing the relation (setDetails
) while in article 2 entity that doesn't havemappedBy
is managing the relation (addTag
/removeTag
) are both approaches valid?
– Kamil
Mar 28 at 16:10
Both articles are correct. You are comparing a one-to-one association to a many-to-many one, hence your confusion. A many to many association is between 2 parents while the one-to-one is a parent-child one. MappedBy is just a flag marking the source of truth in a bidirectional association. That's it and it has nothing to do with cascading.
– Vlad Mihalcea
Mar 28 at 16:32
So what you're saying is: a) The "Owner" of the relation is the entity which table containt ForeignKey b) The "Parent" of the relation is up to the business c) "Parent" and "Owner" are completly orthogonal and unrelated to each other, Hence: 1) I can have cascades on both "mappedBy" and inverse side? and 2) cascades are related to "Parent" and 3) cascases are not related to "Owner" of the relation (mappedBy)? Am I 100% Correct?
– Kamil
Mar 28 at 16:48
No, that's not what I said.
– Vlad Mihalcea
Mar 28 at 16:56
|
show 4 more comments
The mappedBy
attribute marks the side of a bidirectional association which does not own the association. Usually, that's the side which does not have the Foreign Key.
On the other hand, cascading entity state transitions only makes sense from parents to child entities. Doing the cascade from the child entity where the FK is stored is a code smell.
It's as simple as that.
The mappedBy
attribute marks the side of a bidirectional association which does not own the association. Usually, that's the side which does not have the Foreign Key.
On the other hand, cascading entity state transitions only makes sense from parents to child entities. Doing the cascade from the child entity where the FK is stored is a code smell.
It's as simple as that.
answered Mar 28 at 15:52
Vlad MihalceaVlad Mihalcea
66.8k14 gold badges194 silver badges527 bronze badges
66.8k14 gold badges194 silver badges527 bronze badges
Vlad, Let's say this is article 1 and this is article 2 In article 1Post
hasmappedBy
toPostDetails
while in article 2Tag
has mappedBy toPost
. Article 2 seems to be correct while Article 1 seems to be incorrect. Am I wrong? If yes - could you point me to the article (or chapter of your book) that explains why?
– Kamil
Mar 28 at 16:07
Moreover: in article 1 entity that hasmappedBy
is managing the relation (setDetails
) while in article 2 entity that doesn't havemappedBy
is managing the relation (addTag
/removeTag
) are both approaches valid?
– Kamil
Mar 28 at 16:10
Both articles are correct. You are comparing a one-to-one association to a many-to-many one, hence your confusion. A many to many association is between 2 parents while the one-to-one is a parent-child one. MappedBy is just a flag marking the source of truth in a bidirectional association. That's it and it has nothing to do with cascading.
– Vlad Mihalcea
Mar 28 at 16:32
So what you're saying is: a) The "Owner" of the relation is the entity which table containt ForeignKey b) The "Parent" of the relation is up to the business c) "Parent" and "Owner" are completly orthogonal and unrelated to each other, Hence: 1) I can have cascades on both "mappedBy" and inverse side? and 2) cascades are related to "Parent" and 3) cascases are not related to "Owner" of the relation (mappedBy)? Am I 100% Correct?
– Kamil
Mar 28 at 16:48
No, that's not what I said.
– Vlad Mihalcea
Mar 28 at 16:56
|
show 4 more comments
Vlad, Let's say this is article 1 and this is article 2 In article 1Post
hasmappedBy
toPostDetails
while in article 2Tag
has mappedBy toPost
. Article 2 seems to be correct while Article 1 seems to be incorrect. Am I wrong? If yes - could you point me to the article (or chapter of your book) that explains why?
– Kamil
Mar 28 at 16:07
Moreover: in article 1 entity that hasmappedBy
is managing the relation (setDetails
) while in article 2 entity that doesn't havemappedBy
is managing the relation (addTag
/removeTag
) are both approaches valid?
– Kamil
Mar 28 at 16:10
Both articles are correct. You are comparing a one-to-one association to a many-to-many one, hence your confusion. A many to many association is between 2 parents while the one-to-one is a parent-child one. MappedBy is just a flag marking the source of truth in a bidirectional association. That's it and it has nothing to do with cascading.
– Vlad Mihalcea
Mar 28 at 16:32
So what you're saying is: a) The "Owner" of the relation is the entity which table containt ForeignKey b) The "Parent" of the relation is up to the business c) "Parent" and "Owner" are completly orthogonal and unrelated to each other, Hence: 1) I can have cascades on both "mappedBy" and inverse side? and 2) cascades are related to "Parent" and 3) cascases are not related to "Owner" of the relation (mappedBy)? Am I 100% Correct?
– Kamil
Mar 28 at 16:48
No, that's not what I said.
– Vlad Mihalcea
Mar 28 at 16:56
Vlad, Let's say this is article 1 and this is article 2 In article 1
Post
has mappedBy
to PostDetails
while in article 2 Tag
has mappedBy to Post
. Article 2 seems to be correct while Article 1 seems to be incorrect. Am I wrong? If yes - could you point me to the article (or chapter of your book) that explains why?– Kamil
Mar 28 at 16:07
Vlad, Let's say this is article 1 and this is article 2 In article 1
Post
has mappedBy
to PostDetails
while in article 2 Tag
has mappedBy to Post
. Article 2 seems to be correct while Article 1 seems to be incorrect. Am I wrong? If yes - could you point me to the article (or chapter of your book) that explains why?– Kamil
Mar 28 at 16:07
Moreover: in article 1 entity that has
mappedBy
is managing the relation (setDetails
) while in article 2 entity that doesn't have mappedBy
is managing the relation (addTag
/ removeTag
) are both approaches valid?– Kamil
Mar 28 at 16:10
Moreover: in article 1 entity that has
mappedBy
is managing the relation (setDetails
) while in article 2 entity that doesn't have mappedBy
is managing the relation (addTag
/ removeTag
) are both approaches valid?– Kamil
Mar 28 at 16:10
Both articles are correct. You are comparing a one-to-one association to a many-to-many one, hence your confusion. A many to many association is between 2 parents while the one-to-one is a parent-child one. MappedBy is just a flag marking the source of truth in a bidirectional association. That's it and it has nothing to do with cascading.
– Vlad Mihalcea
Mar 28 at 16:32
Both articles are correct. You are comparing a one-to-one association to a many-to-many one, hence your confusion. A many to many association is between 2 parents while the one-to-one is a parent-child one. MappedBy is just a flag marking the source of truth in a bidirectional association. That's it and it has nothing to do with cascading.
– Vlad Mihalcea
Mar 28 at 16:32
So what you're saying is: a) The "Owner" of the relation is the entity which table containt ForeignKey b) The "Parent" of the relation is up to the business c) "Parent" and "Owner" are completly orthogonal and unrelated to each other, Hence: 1) I can have cascades on both "mappedBy" and inverse side? and 2) cascades are related to "Parent" and 3) cascases are not related to "Owner" of the relation (mappedBy)? Am I 100% Correct?
– Kamil
Mar 28 at 16:48
So what you're saying is: a) The "Owner" of the relation is the entity which table containt ForeignKey b) The "Parent" of the relation is up to the business c) "Parent" and "Owner" are completly orthogonal and unrelated to each other, Hence: 1) I can have cascades on both "mappedBy" and inverse side? and 2) cascades are related to "Parent" and 3) cascases are not related to "Owner" of the relation (mappedBy)? Am I 100% Correct?
– Kamil
Mar 28 at 16:48
No, that's not what I said.
– Vlad Mihalcea
Mar 28 at 16:56
No, that's not what I said.
– Vlad Mihalcea
Mar 28 at 16:56
|
show 4 more comments
- In database there should be user_id in address table table, right? Who is the owner of the relation then?
- Exactly. Basically, the owner is address, as it's the owner who holds the reference.
- In entities: which one should have mappedBy - User or Address?
@ManyToOne
doesn't even have the attribute mappedBy. It's present only on xToMany annotations.
Your mapping should be:
@Table(name = "users")
public class User
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
@OneToMany(mappedBy="user", cascade = ...) // atenttion, this refer the attribute name as opposed to the column name
private Set<Address> addresses = new HashSet<>();
@Table(name = "addresses")
public class Address
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
@ManyToOne
@JoinColumn(name="user_id") // the name is optional if you refer to the PK
private User user;
On which side (User or Address?) the @ManyToMany(cascade = CascadeType.MERGE, CascadeType.DETACH, CascadeType.REFRESH) should be placed?
And last question: which of the entities should manage the relation like this:
In this case, you want to handle User, and then JPA handles Address automatically.
Therefore, the cascade would be on User.
On this side (OneToMany), you probably also want to add orphanRemoval = true
.
Trying to adjust after clarification...
About the support, JPA supports cascading from both sides, ok?!
From where you should use it depends on your domain.
You are supposed to use it on the Entity which you use on entityManager operations, for instance: em.persist(user)
or em.merge(address)
.
Really, depends on how your code is.
In this specify case, it seems it makes more sense to leave on User. I suppose you have an User CRUD, which also includes address.
In this case, it makes sense when you create or remove an User, then its addresses are created/remove together.
On the other side, it wouldn't make sense to cascade from the Address. If you remove an Address, it does NOT mean that the user should be removed too.
Can you see?! You need to check your use case. The side to use it (whether oneToMany or manyToOne or ...) should be thought and decided based on your needs on that moment.
thank you for your answer. Two questions: 1) Are you sure that the side with mappedBy whould manage cascades? 2) Which of the class should set the opposite in setters: User like this like in my example or Address?
– Kamil
Mar 28 at 15:00
Hey! 1. Yes, JPA is capable of handling that cascading. 2. Yeah, you also need to set the user instance on you Address, exactly the way you did onaddAddress
. I think JPA could be smarter in this point
– Ricardo Silva
Mar 28 at 15:20
1) I changed my main question because you were misleaded by OneToMany used in the example. I would apprieciate if you could read the new version of the question. 2) I'm aware that JPA can handle cascades, but the question is "On whcich side cascade should happed" - where mappedBy is or the inverse? There are sources that say exactly the opposite 3) Also the question is not if I should set instance but "On which side" - mappedBy is or the inverse?
– Kamil
Mar 28 at 15:33
OK. I changed it. I hope it's a little clearer now
– Ricardo Silva
Mar 28 at 16:04
Thak you for your help
– Kamil
Mar 28 at 16:54
add a comment
|
- In database there should be user_id in address table table, right? Who is the owner of the relation then?
- Exactly. Basically, the owner is address, as it's the owner who holds the reference.
- In entities: which one should have mappedBy - User or Address?
@ManyToOne
doesn't even have the attribute mappedBy. It's present only on xToMany annotations.
Your mapping should be:
@Table(name = "users")
public class User
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
@OneToMany(mappedBy="user", cascade = ...) // atenttion, this refer the attribute name as opposed to the column name
private Set<Address> addresses = new HashSet<>();
@Table(name = "addresses")
public class Address
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
@ManyToOne
@JoinColumn(name="user_id") // the name is optional if you refer to the PK
private User user;
On which side (User or Address?) the @ManyToMany(cascade = CascadeType.MERGE, CascadeType.DETACH, CascadeType.REFRESH) should be placed?
And last question: which of the entities should manage the relation like this:
In this case, you want to handle User, and then JPA handles Address automatically.
Therefore, the cascade would be on User.
On this side (OneToMany), you probably also want to add orphanRemoval = true
.
Trying to adjust after clarification...
About the support, JPA supports cascading from both sides, ok?!
From where you should use it depends on your domain.
You are supposed to use it on the Entity which you use on entityManager operations, for instance: em.persist(user)
or em.merge(address)
.
Really, depends on how your code is.
In this specify case, it seems it makes more sense to leave on User. I suppose you have an User CRUD, which also includes address.
In this case, it makes sense when you create or remove an User, then its addresses are created/remove together.
On the other side, it wouldn't make sense to cascade from the Address. If you remove an Address, it does NOT mean that the user should be removed too.
Can you see?! You need to check your use case. The side to use it (whether oneToMany or manyToOne or ...) should be thought and decided based on your needs on that moment.
thank you for your answer. Two questions: 1) Are you sure that the side with mappedBy whould manage cascades? 2) Which of the class should set the opposite in setters: User like this like in my example or Address?
– Kamil
Mar 28 at 15:00
Hey! 1. Yes, JPA is capable of handling that cascading. 2. Yeah, you also need to set the user instance on you Address, exactly the way you did onaddAddress
. I think JPA could be smarter in this point
– Ricardo Silva
Mar 28 at 15:20
1) I changed my main question because you were misleaded by OneToMany used in the example. I would apprieciate if you could read the new version of the question. 2) I'm aware that JPA can handle cascades, but the question is "On whcich side cascade should happed" - where mappedBy is or the inverse? There are sources that say exactly the opposite 3) Also the question is not if I should set instance but "On which side" - mappedBy is or the inverse?
– Kamil
Mar 28 at 15:33
OK. I changed it. I hope it's a little clearer now
– Ricardo Silva
Mar 28 at 16:04
Thak you for your help
– Kamil
Mar 28 at 16:54
add a comment
|
- In database there should be user_id in address table table, right? Who is the owner of the relation then?
- Exactly. Basically, the owner is address, as it's the owner who holds the reference.
- In entities: which one should have mappedBy - User or Address?
@ManyToOne
doesn't even have the attribute mappedBy. It's present only on xToMany annotations.
Your mapping should be:
@Table(name = "users")
public class User
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
@OneToMany(mappedBy="user", cascade = ...) // atenttion, this refer the attribute name as opposed to the column name
private Set<Address> addresses = new HashSet<>();
@Table(name = "addresses")
public class Address
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
@ManyToOne
@JoinColumn(name="user_id") // the name is optional if you refer to the PK
private User user;
On which side (User or Address?) the @ManyToMany(cascade = CascadeType.MERGE, CascadeType.DETACH, CascadeType.REFRESH) should be placed?
And last question: which of the entities should manage the relation like this:
In this case, you want to handle User, and then JPA handles Address automatically.
Therefore, the cascade would be on User.
On this side (OneToMany), you probably also want to add orphanRemoval = true
.
Trying to adjust after clarification...
About the support, JPA supports cascading from both sides, ok?!
From where you should use it depends on your domain.
You are supposed to use it on the Entity which you use on entityManager operations, for instance: em.persist(user)
or em.merge(address)
.
Really, depends on how your code is.
In this specify case, it seems it makes more sense to leave on User. I suppose you have an User CRUD, which also includes address.
In this case, it makes sense when you create or remove an User, then its addresses are created/remove together.
On the other side, it wouldn't make sense to cascade from the Address. If you remove an Address, it does NOT mean that the user should be removed too.
Can you see?! You need to check your use case. The side to use it (whether oneToMany or manyToOne or ...) should be thought and decided based on your needs on that moment.
- In database there should be user_id in address table table, right? Who is the owner of the relation then?
- Exactly. Basically, the owner is address, as it's the owner who holds the reference.
- In entities: which one should have mappedBy - User or Address?
@ManyToOne
doesn't even have the attribute mappedBy. It's present only on xToMany annotations.
Your mapping should be:
@Table(name = "users")
public class User
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
@OneToMany(mappedBy="user", cascade = ...) // atenttion, this refer the attribute name as opposed to the column name
private Set<Address> addresses = new HashSet<>();
@Table(name = "addresses")
public class Address
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
@ManyToOne
@JoinColumn(name="user_id") // the name is optional if you refer to the PK
private User user;
On which side (User or Address?) the @ManyToMany(cascade = CascadeType.MERGE, CascadeType.DETACH, CascadeType.REFRESH) should be placed?
And last question: which of the entities should manage the relation like this:
In this case, you want to handle User, and then JPA handles Address automatically.
Therefore, the cascade would be on User.
On this side (OneToMany), you probably also want to add orphanRemoval = true
.
Trying to adjust after clarification...
About the support, JPA supports cascading from both sides, ok?!
From where you should use it depends on your domain.
You are supposed to use it on the Entity which you use on entityManager operations, for instance: em.persist(user)
or em.merge(address)
.
Really, depends on how your code is.
In this specify case, it seems it makes more sense to leave on User. I suppose you have an User CRUD, which also includes address.
In this case, it makes sense when you create or remove an User, then its addresses are created/remove together.
On the other side, it wouldn't make sense to cascade from the Address. If you remove an Address, it does NOT mean that the user should be removed too.
Can you see?! You need to check your use case. The side to use it (whether oneToMany or manyToOne or ...) should be thought and decided based on your needs on that moment.
edited Mar 28 at 16:03
answered Mar 28 at 14:50
Ricardo SilvaRicardo Silva
1,6611 gold badge14 silver badges20 bronze badges
1,6611 gold badge14 silver badges20 bronze badges
thank you for your answer. Two questions: 1) Are you sure that the side with mappedBy whould manage cascades? 2) Which of the class should set the opposite in setters: User like this like in my example or Address?
– Kamil
Mar 28 at 15:00
Hey! 1. Yes, JPA is capable of handling that cascading. 2. Yeah, you also need to set the user instance on you Address, exactly the way you did onaddAddress
. I think JPA could be smarter in this point
– Ricardo Silva
Mar 28 at 15:20
1) I changed my main question because you were misleaded by OneToMany used in the example. I would apprieciate if you could read the new version of the question. 2) I'm aware that JPA can handle cascades, but the question is "On whcich side cascade should happed" - where mappedBy is or the inverse? There are sources that say exactly the opposite 3) Also the question is not if I should set instance but "On which side" - mappedBy is or the inverse?
– Kamil
Mar 28 at 15:33
OK. I changed it. I hope it's a little clearer now
– Ricardo Silva
Mar 28 at 16:04
Thak you for your help
– Kamil
Mar 28 at 16:54
add a comment
|
thank you for your answer. Two questions: 1) Are you sure that the side with mappedBy whould manage cascades? 2) Which of the class should set the opposite in setters: User like this like in my example or Address?
– Kamil
Mar 28 at 15:00
Hey! 1. Yes, JPA is capable of handling that cascading. 2. Yeah, you also need to set the user instance on you Address, exactly the way you did onaddAddress
. I think JPA could be smarter in this point
– Ricardo Silva
Mar 28 at 15:20
1) I changed my main question because you were misleaded by OneToMany used in the example. I would apprieciate if you could read the new version of the question. 2) I'm aware that JPA can handle cascades, but the question is "On whcich side cascade should happed" - where mappedBy is or the inverse? There are sources that say exactly the opposite 3) Also the question is not if I should set instance but "On which side" - mappedBy is or the inverse?
– Kamil
Mar 28 at 15:33
OK. I changed it. I hope it's a little clearer now
– Ricardo Silva
Mar 28 at 16:04
Thak you for your help
– Kamil
Mar 28 at 16:54
thank you for your answer. Two questions: 1) Are you sure that the side with mappedBy whould manage cascades? 2) Which of the class should set the opposite in setters: User like this like in my example or Address?
– Kamil
Mar 28 at 15:00
thank you for your answer. Two questions: 1) Are you sure that the side with mappedBy whould manage cascades? 2) Which of the class should set the opposite in setters: User like this like in my example or Address?
– Kamil
Mar 28 at 15:00
Hey! 1. Yes, JPA is capable of handling that cascading. 2. Yeah, you also need to set the user instance on you Address, exactly the way you did on
addAddress
. I think JPA could be smarter in this point– Ricardo Silva
Mar 28 at 15:20
Hey! 1. Yes, JPA is capable of handling that cascading. 2. Yeah, you also need to set the user instance on you Address, exactly the way you did on
addAddress
. I think JPA could be smarter in this point– Ricardo Silva
Mar 28 at 15:20
1) I changed my main question because you were misleaded by OneToMany used in the example. I would apprieciate if you could read the new version of the question. 2) I'm aware that JPA can handle cascades, but the question is "On whcich side cascade should happed" - where mappedBy is or the inverse? There are sources that say exactly the opposite 3) Also the question is not if I should set instance but "On which side" - mappedBy is or the inverse?
– Kamil
Mar 28 at 15:33
1) I changed my main question because you were misleaded by OneToMany used in the example. I would apprieciate if you could read the new version of the question. 2) I'm aware that JPA can handle cascades, but the question is "On whcich side cascade should happed" - where mappedBy is or the inverse? There are sources that say exactly the opposite 3) Also the question is not if I should set instance but "On which side" - mappedBy is or the inverse?
– Kamil
Mar 28 at 15:33
OK. I changed it. I hope it's a little clearer now
– Ricardo Silva
Mar 28 at 16:04
OK. I changed it. I hope it's a little clearer now
– Ricardo Silva
Mar 28 at 16:04
Thak you for your help
– Kamil
Mar 28 at 16:54
Thak you for your help
– Kamil
Mar 28 at 16:54
add a comment
|
This is what I have learnt so far.
If I'm mistaken to any of the points - please let me know in comments, and I edit the answer.
Database
Owner of the relation
`According to this answer
Basically, the owner is address, as it's the owner who holds the reference.
So the "owner
" of relation in database is entity with foreign key - Address
in case of OneToOne/OneToMany.
Moreover - it seems that in the same time "owner
" of the database relation is the Child
in Hibernate relation - but I need confirmation for this
OneToOne
Parent/Child
According to this article
The Post entity is the parent, while the PostDetails is the child association because the Foreign Key is located in the post_details database table
So User
is the Parent
and Address
is the Child
here (because Address
holds foreign key)
mappedBy
According to this answer
The mappedBy attribute marks the side of a bidirectional association which does not own the association. Usually, that's the side which does not have the Foreign Key.
So mappedBy
should be placed in User
, because foreign key
is in Address
.
In seems that in @OneToOne
mappedBy
should be always placed in Parent
(entity not holding the foreign key)
JoinColumn
It seems that JoinColumn
in OneToOne
must be always placed in Child
(since it holds foreign key)
Cascades
According to this answer
cascading entity state transitions only makes sense from parents to child entities.
So cascades
in OneToOne
should be always done in Parent
, so - according to previous links - User
in this example
set utility method
I'm not sure but it seems that utility setter should be placed in User
.
Is it always placed in the Parent
?
Outcome
CREATE SEQUENCE IF NOT EXISTS hibernate_sequence;
CREATE TABLE users (
id BIGINT PRIMARY KEY
);
CREATE TABLE addresses (
id BIGINT PRIMARY KEY,
user_id BIGINT NOT NULL UNIQUE CONSTRAINT fk_addresses_user_id REFERENCES users(id) ON DELETE CASCADE,
);
@Table(name = "users")
public class User
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
@OneToOne(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY, optional = false, orphanRemoval = true)
private Address address;
public void setAddress(Address address)
if (address != null)
address.setUser(this);
this.address = address;
@Table(name = "addresses")
public class Address
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User user;
OneToMany
Parent/Child
It seems to be the same as with OneToOne
, so User
is the Parent
and Address
is the Child
(because it has foreign key), but I'm not 100% sure...
mappedBy
In this article mappedBy
is placed in Parent
(but I'm not sure if this is the rule of thumb though)
JoinColumn
It seems that JoinColumn
in OneToMany
must be always placed in Child
(since it holds foreign key)
Cascades
In above article cascades
are also placed in Parent
(but I'm not sure if this is the rule of thumb as well)
add/remove utility methods
In above article utility methods
are also placed in Parent
(but I'm not sure if this is the rule of thumb as well)
Outcome
CREATE SEQUENCE IF NOT EXISTS hibernate_sequence;
CREATE TABLE users (
id BIGINT PRIMARY KEY
);
CREATE TABLE addresses (
id BIGINT PRIMARY KEY,
user_id BIGINT NOT NULL CONSTRAINT fk_addresses_user_id REFERENCES users(id) ON DELETE CASCADE,
);
@Table(name = "users")
public class User
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
private List<Address> addresses = new ArrayList<>();
public void addAddress(Address address)
if (address != null)
address.setUser(this);
this.addresses.add(address);
public void removeAddress(Address address)
this.addresses.remove(address);
if (address != null)
address.setUser(null);
public Set<Address> getAddresses()
return Collections.unmodifiableSet(this.addresses);
@Table(name = "addresses")
public class Address
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User user;
ManyToMany
Parent/Child
According to this article
A typical many-to-many database association includes two parent tables
So both User
and Address
are Parents
mappedBy
In the same article Vlad wrote:
The mappedBy attribute of the posts association in the Tag entity marks that, in this bidirectional relationship, the Post entity own the association
Therefore here is the eception, because we don't have one Parent
.
It is not clear to me what Vlad means exactly by "own", but if User
"owns" the relation, mappedBy
must be placed in Address
,
JoinTable
It seems that JoinTable
must be always placed in entity that "owns" the relation, so User
in this case.
Am I right?
Cascades
According to the same article cascades
should be always placed in "owner" defined above, so User
in this case.
Also important thing to notice is that we can not use REMOVE
cascade
add/remove utility methods
It seems that add/remove utility methods
should be placed in User
.
Is this the rule of thumb, that utility methods
should be alway placed in entity that "owns" the relation?
Outcome
CREATE SEQUENCE IF NOT EXISTS hibernate_sequence;
CREATE TABLE users (
id BIGINT PRIMARY KEY
);
CREATE TABLE addresses (
id BIGINT PRIMARY KEY,
);
CREATE TABLE users_addresses (
user_id BIGINT NOT NULL CONSTRAINT fk_users_addresses_user_id REFERENCES users(id) ON DELETE CASCADE,
address_id BIGINT NOT NULL CONSTRAINT fk_users_addresses_address_id REFERENCES addresses(id) ON DELETE CASCADE,
PRIMARY KEY(user_id,address_id)
);
@Table(name = "users")
public class User
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
@ManyToMany(cascade =
CascadeType.PERSIST,
CascadeType.MERGE
)
@JoinTable(name = "post_tag",
joinColumns = @JoinColumn(name = "post_id"),
inverseJoinColumns = @JoinColumn(name = "tag_id")
)
private List<Address> addresses = new ArrayList<>();
public void addAddress(Address address)
addresses.add(address);
address.getUsers().add(this);
public void removeAddress(Address address)
addresses.remove(address);
address.getUsers().remove(this);
@Table(name = "addresses")
public class Address
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
@ManyToMany(mappedBy = "addresses")
private List<User> users = new ArrayList<>();
Summary
I think this table sums it up: https://i.ibb.co/zNjZ3md/JPA-relations.png
The last thing I don't unserstand is:
- why Vlad in this article in "ManyToMany" section uses
mappedBy
inAuthor
("owner") instead ofBook
(especially that it throws exception in my code) - why in javadoc
mappedBy
is onCustomerRecord
(child) not onCustomer
(but here maybe foreign key is located in Customer, so although counter intuitive - it is correct)
add a comment
|
This is what I have learnt so far.
If I'm mistaken to any of the points - please let me know in comments, and I edit the answer.
Database
Owner of the relation
`According to this answer
Basically, the owner is address, as it's the owner who holds the reference.
So the "owner
" of relation in database is entity with foreign key - Address
in case of OneToOne/OneToMany.
Moreover - it seems that in the same time "owner
" of the database relation is the Child
in Hibernate relation - but I need confirmation for this
OneToOne
Parent/Child
According to this article
The Post entity is the parent, while the PostDetails is the child association because the Foreign Key is located in the post_details database table
So User
is the Parent
and Address
is the Child
here (because Address
holds foreign key)
mappedBy
According to this answer
The mappedBy attribute marks the side of a bidirectional association which does not own the association. Usually, that's the side which does not have the Foreign Key.
So mappedBy
should be placed in User
, because foreign key
is in Address
.
In seems that in @OneToOne
mappedBy
should be always placed in Parent
(entity not holding the foreign key)
JoinColumn
It seems that JoinColumn
in OneToOne
must be always placed in Child
(since it holds foreign key)
Cascades
According to this answer
cascading entity state transitions only makes sense from parents to child entities.
So cascades
in OneToOne
should be always done in Parent
, so - according to previous links - User
in this example
set utility method
I'm not sure but it seems that utility setter should be placed in User
.
Is it always placed in the Parent
?
Outcome
CREATE SEQUENCE IF NOT EXISTS hibernate_sequence;
CREATE TABLE users (
id BIGINT PRIMARY KEY
);
CREATE TABLE addresses (
id BIGINT PRIMARY KEY,
user_id BIGINT NOT NULL UNIQUE CONSTRAINT fk_addresses_user_id REFERENCES users(id) ON DELETE CASCADE,
);
@Table(name = "users")
public class User
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
@OneToOne(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY, optional = false, orphanRemoval = true)
private Address address;
public void setAddress(Address address)
if (address != null)
address.setUser(this);
this.address = address;
@Table(name = "addresses")
public class Address
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User user;
OneToMany
Parent/Child
It seems to be the same as with OneToOne
, so User
is the Parent
and Address
is the Child
(because it has foreign key), but I'm not 100% sure...
mappedBy
In this article mappedBy
is placed in Parent
(but I'm not sure if this is the rule of thumb though)
JoinColumn
It seems that JoinColumn
in OneToMany
must be always placed in Child
(since it holds foreign key)
Cascades
In above article cascades
are also placed in Parent
(but I'm not sure if this is the rule of thumb as well)
add/remove utility methods
In above article utility methods
are also placed in Parent
(but I'm not sure if this is the rule of thumb as well)
Outcome
CREATE SEQUENCE IF NOT EXISTS hibernate_sequence;
CREATE TABLE users (
id BIGINT PRIMARY KEY
);
CREATE TABLE addresses (
id BIGINT PRIMARY KEY,
user_id BIGINT NOT NULL CONSTRAINT fk_addresses_user_id REFERENCES users(id) ON DELETE CASCADE,
);
@Table(name = "users")
public class User
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
private List<Address> addresses = new ArrayList<>();
public void addAddress(Address address)
if (address != null)
address.setUser(this);
this.addresses.add(address);
public void removeAddress(Address address)
this.addresses.remove(address);
if (address != null)
address.setUser(null);
public Set<Address> getAddresses()
return Collections.unmodifiableSet(this.addresses);
@Table(name = "addresses")
public class Address
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User user;
ManyToMany
Parent/Child
According to this article
A typical many-to-many database association includes two parent tables
So both User
and Address
are Parents
mappedBy
In the same article Vlad wrote:
The mappedBy attribute of the posts association in the Tag entity marks that, in this bidirectional relationship, the Post entity own the association
Therefore here is the eception, because we don't have one Parent
.
It is not clear to me what Vlad means exactly by "own", but if User
"owns" the relation, mappedBy
must be placed in Address
,
JoinTable
It seems that JoinTable
must be always placed in entity that "owns" the relation, so User
in this case.
Am I right?
Cascades
According to the same article cascades
should be always placed in "owner" defined above, so User
in this case.
Also important thing to notice is that we can not use REMOVE
cascade
add/remove utility methods
It seems that add/remove utility methods
should be placed in User
.
Is this the rule of thumb, that utility methods
should be alway placed in entity that "owns" the relation?
Outcome
CREATE SEQUENCE IF NOT EXISTS hibernate_sequence;
CREATE TABLE users (
id BIGINT PRIMARY KEY
);
CREATE TABLE addresses (
id BIGINT PRIMARY KEY,
);
CREATE TABLE users_addresses (
user_id BIGINT NOT NULL CONSTRAINT fk_users_addresses_user_id REFERENCES users(id) ON DELETE CASCADE,
address_id BIGINT NOT NULL CONSTRAINT fk_users_addresses_address_id REFERENCES addresses(id) ON DELETE CASCADE,
PRIMARY KEY(user_id,address_id)
);
@Table(name = "users")
public class User
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
@ManyToMany(cascade =
CascadeType.PERSIST,
CascadeType.MERGE
)
@JoinTable(name = "post_tag",
joinColumns = @JoinColumn(name = "post_id"),
inverseJoinColumns = @JoinColumn(name = "tag_id")
)
private List<Address> addresses = new ArrayList<>();
public void addAddress(Address address)
addresses.add(address);
address.getUsers().add(this);
public void removeAddress(Address address)
addresses.remove(address);
address.getUsers().remove(this);
@Table(name = "addresses")
public class Address
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
@ManyToMany(mappedBy = "addresses")
private List<User> users = new ArrayList<>();
Summary
I think this table sums it up: https://i.ibb.co/zNjZ3md/JPA-relations.png
The last thing I don't unserstand is:
- why Vlad in this article in "ManyToMany" section uses
mappedBy
inAuthor
("owner") instead ofBook
(especially that it throws exception in my code) - why in javadoc
mappedBy
is onCustomerRecord
(child) not onCustomer
(but here maybe foreign key is located in Customer, so although counter intuitive - it is correct)
add a comment
|
This is what I have learnt so far.
If I'm mistaken to any of the points - please let me know in comments, and I edit the answer.
Database
Owner of the relation
`According to this answer
Basically, the owner is address, as it's the owner who holds the reference.
So the "owner
" of relation in database is entity with foreign key - Address
in case of OneToOne/OneToMany.
Moreover - it seems that in the same time "owner
" of the database relation is the Child
in Hibernate relation - but I need confirmation for this
OneToOne
Parent/Child
According to this article
The Post entity is the parent, while the PostDetails is the child association because the Foreign Key is located in the post_details database table
So User
is the Parent
and Address
is the Child
here (because Address
holds foreign key)
mappedBy
According to this answer
The mappedBy attribute marks the side of a bidirectional association which does not own the association. Usually, that's the side which does not have the Foreign Key.
So mappedBy
should be placed in User
, because foreign key
is in Address
.
In seems that in @OneToOne
mappedBy
should be always placed in Parent
(entity not holding the foreign key)
JoinColumn
It seems that JoinColumn
in OneToOne
must be always placed in Child
(since it holds foreign key)
Cascades
According to this answer
cascading entity state transitions only makes sense from parents to child entities.
So cascades
in OneToOne
should be always done in Parent
, so - according to previous links - User
in this example
set utility method
I'm not sure but it seems that utility setter should be placed in User
.
Is it always placed in the Parent
?
Outcome
CREATE SEQUENCE IF NOT EXISTS hibernate_sequence;
CREATE TABLE users (
id BIGINT PRIMARY KEY
);
CREATE TABLE addresses (
id BIGINT PRIMARY KEY,
user_id BIGINT NOT NULL UNIQUE CONSTRAINT fk_addresses_user_id REFERENCES users(id) ON DELETE CASCADE,
);
@Table(name = "users")
public class User
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
@OneToOne(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY, optional = false, orphanRemoval = true)
private Address address;
public void setAddress(Address address)
if (address != null)
address.setUser(this);
this.address = address;
@Table(name = "addresses")
public class Address
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User user;
OneToMany
Parent/Child
It seems to be the same as with OneToOne
, so User
is the Parent
and Address
is the Child
(because it has foreign key), but I'm not 100% sure...
mappedBy
In this article mappedBy
is placed in Parent
(but I'm not sure if this is the rule of thumb though)
JoinColumn
It seems that JoinColumn
in OneToMany
must be always placed in Child
(since it holds foreign key)
Cascades
In above article cascades
are also placed in Parent
(but I'm not sure if this is the rule of thumb as well)
add/remove utility methods
In above article utility methods
are also placed in Parent
(but I'm not sure if this is the rule of thumb as well)
Outcome
CREATE SEQUENCE IF NOT EXISTS hibernate_sequence;
CREATE TABLE users (
id BIGINT PRIMARY KEY
);
CREATE TABLE addresses (
id BIGINT PRIMARY KEY,
user_id BIGINT NOT NULL CONSTRAINT fk_addresses_user_id REFERENCES users(id) ON DELETE CASCADE,
);
@Table(name = "users")
public class User
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
private List<Address> addresses = new ArrayList<>();
public void addAddress(Address address)
if (address != null)
address.setUser(this);
this.addresses.add(address);
public void removeAddress(Address address)
this.addresses.remove(address);
if (address != null)
address.setUser(null);
public Set<Address> getAddresses()
return Collections.unmodifiableSet(this.addresses);
@Table(name = "addresses")
public class Address
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User user;
ManyToMany
Parent/Child
According to this article
A typical many-to-many database association includes two parent tables
So both User
and Address
are Parents
mappedBy
In the same article Vlad wrote:
The mappedBy attribute of the posts association in the Tag entity marks that, in this bidirectional relationship, the Post entity own the association
Therefore here is the eception, because we don't have one Parent
.
It is not clear to me what Vlad means exactly by "own", but if User
"owns" the relation, mappedBy
must be placed in Address
,
JoinTable
It seems that JoinTable
must be always placed in entity that "owns" the relation, so User
in this case.
Am I right?
Cascades
According to the same article cascades
should be always placed in "owner" defined above, so User
in this case.
Also important thing to notice is that we can not use REMOVE
cascade
add/remove utility methods
It seems that add/remove utility methods
should be placed in User
.
Is this the rule of thumb, that utility methods
should be alway placed in entity that "owns" the relation?
Outcome
CREATE SEQUENCE IF NOT EXISTS hibernate_sequence;
CREATE TABLE users (
id BIGINT PRIMARY KEY
);
CREATE TABLE addresses (
id BIGINT PRIMARY KEY,
);
CREATE TABLE users_addresses (
user_id BIGINT NOT NULL CONSTRAINT fk_users_addresses_user_id REFERENCES users(id) ON DELETE CASCADE,
address_id BIGINT NOT NULL CONSTRAINT fk_users_addresses_address_id REFERENCES addresses(id) ON DELETE CASCADE,
PRIMARY KEY(user_id,address_id)
);
@Table(name = "users")
public class User
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
@ManyToMany(cascade =
CascadeType.PERSIST,
CascadeType.MERGE
)
@JoinTable(name = "post_tag",
joinColumns = @JoinColumn(name = "post_id"),
inverseJoinColumns = @JoinColumn(name = "tag_id")
)
private List<Address> addresses = new ArrayList<>();
public void addAddress(Address address)
addresses.add(address);
address.getUsers().add(this);
public void removeAddress(Address address)
addresses.remove(address);
address.getUsers().remove(this);
@Table(name = "addresses")
public class Address
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
@ManyToMany(mappedBy = "addresses")
private List<User> users = new ArrayList<>();
Summary
I think this table sums it up: https://i.ibb.co/zNjZ3md/JPA-relations.png
The last thing I don't unserstand is:
- why Vlad in this article in "ManyToMany" section uses
mappedBy
inAuthor
("owner") instead ofBook
(especially that it throws exception in my code) - why in javadoc
mappedBy
is onCustomerRecord
(child) not onCustomer
(but here maybe foreign key is located in Customer, so although counter intuitive - it is correct)
This is what I have learnt so far.
If I'm mistaken to any of the points - please let me know in comments, and I edit the answer.
Database
Owner of the relation
`According to this answer
Basically, the owner is address, as it's the owner who holds the reference.
So the "owner
" of relation in database is entity with foreign key - Address
in case of OneToOne/OneToMany.
Moreover - it seems that in the same time "owner
" of the database relation is the Child
in Hibernate relation - but I need confirmation for this
OneToOne
Parent/Child
According to this article
The Post entity is the parent, while the PostDetails is the child association because the Foreign Key is located in the post_details database table
So User
is the Parent
and Address
is the Child
here (because Address
holds foreign key)
mappedBy
According to this answer
The mappedBy attribute marks the side of a bidirectional association which does not own the association. Usually, that's the side which does not have the Foreign Key.
So mappedBy
should be placed in User
, because foreign key
is in Address
.
In seems that in @OneToOne
mappedBy
should be always placed in Parent
(entity not holding the foreign key)
JoinColumn
It seems that JoinColumn
in OneToOne
must be always placed in Child
(since it holds foreign key)
Cascades
According to this answer
cascading entity state transitions only makes sense from parents to child entities.
So cascades
in OneToOne
should be always done in Parent
, so - according to previous links - User
in this example
set utility method
I'm not sure but it seems that utility setter should be placed in User
.
Is it always placed in the Parent
?
Outcome
CREATE SEQUENCE IF NOT EXISTS hibernate_sequence;
CREATE TABLE users (
id BIGINT PRIMARY KEY
);
CREATE TABLE addresses (
id BIGINT PRIMARY KEY,
user_id BIGINT NOT NULL UNIQUE CONSTRAINT fk_addresses_user_id REFERENCES users(id) ON DELETE CASCADE,
);
@Table(name = "users")
public class User
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
@OneToOne(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY, optional = false, orphanRemoval = true)
private Address address;
public void setAddress(Address address)
if (address != null)
address.setUser(this);
this.address = address;
@Table(name = "addresses")
public class Address
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User user;
OneToMany
Parent/Child
It seems to be the same as with OneToOne
, so User
is the Parent
and Address
is the Child
(because it has foreign key), but I'm not 100% sure...
mappedBy
In this article mappedBy
is placed in Parent
(but I'm not sure if this is the rule of thumb though)
JoinColumn
It seems that JoinColumn
in OneToMany
must be always placed in Child
(since it holds foreign key)
Cascades
In above article cascades
are also placed in Parent
(but I'm not sure if this is the rule of thumb as well)
add/remove utility methods
In above article utility methods
are also placed in Parent
(but I'm not sure if this is the rule of thumb as well)
Outcome
CREATE SEQUENCE IF NOT EXISTS hibernate_sequence;
CREATE TABLE users (
id BIGINT PRIMARY KEY
);
CREATE TABLE addresses (
id BIGINT PRIMARY KEY,
user_id BIGINT NOT NULL CONSTRAINT fk_addresses_user_id REFERENCES users(id) ON DELETE CASCADE,
);
@Table(name = "users")
public class User
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
private List<Address> addresses = new ArrayList<>();
public void addAddress(Address address)
if (address != null)
address.setUser(this);
this.addresses.add(address);
public void removeAddress(Address address)
this.addresses.remove(address);
if (address != null)
address.setUser(null);
public Set<Address> getAddresses()
return Collections.unmodifiableSet(this.addresses);
@Table(name = "addresses")
public class Address
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User user;
ManyToMany
Parent/Child
According to this article
A typical many-to-many database association includes two parent tables
So both User
and Address
are Parents
mappedBy
In the same article Vlad wrote:
The mappedBy attribute of the posts association in the Tag entity marks that, in this bidirectional relationship, the Post entity own the association
Therefore here is the eception, because we don't have one Parent
.
It is not clear to me what Vlad means exactly by "own", but if User
"owns" the relation, mappedBy
must be placed in Address
,
JoinTable
It seems that JoinTable
must be always placed in entity that "owns" the relation, so User
in this case.
Am I right?
Cascades
According to the same article cascades
should be always placed in "owner" defined above, so User
in this case.
Also important thing to notice is that we can not use REMOVE
cascade
add/remove utility methods
It seems that add/remove utility methods
should be placed in User
.
Is this the rule of thumb, that utility methods
should be alway placed in entity that "owns" the relation?
Outcome
CREATE SEQUENCE IF NOT EXISTS hibernate_sequence;
CREATE TABLE users (
id BIGINT PRIMARY KEY
);
CREATE TABLE addresses (
id BIGINT PRIMARY KEY,
);
CREATE TABLE users_addresses (
user_id BIGINT NOT NULL CONSTRAINT fk_users_addresses_user_id REFERENCES users(id) ON DELETE CASCADE,
address_id BIGINT NOT NULL CONSTRAINT fk_users_addresses_address_id REFERENCES addresses(id) ON DELETE CASCADE,
PRIMARY KEY(user_id,address_id)
);
@Table(name = "users")
public class User
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
@ManyToMany(cascade =
CascadeType.PERSIST,
CascadeType.MERGE
)
@JoinTable(name = "post_tag",
joinColumns = @JoinColumn(name = "post_id"),
inverseJoinColumns = @JoinColumn(name = "tag_id")
)
private List<Address> addresses = new ArrayList<>();
public void addAddress(Address address)
addresses.add(address);
address.getUsers().add(this);
public void removeAddress(Address address)
addresses.remove(address);
address.getUsers().remove(this);
@Table(name = "addresses")
public class Address
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
@ManyToMany(mappedBy = "addresses")
private List<User> users = new ArrayList<>();
Summary
I think this table sums it up: https://i.ibb.co/zNjZ3md/JPA-relations.png
The last thing I don't unserstand is:
- why Vlad in this article in "ManyToMany" section uses
mappedBy
inAuthor
("owner") instead ofBook
(especially that it throws exception in my code) - why in javadoc
mappedBy
is onCustomerRecord
(child) not onCustomer
(but here maybe foreign key is located in Customer, so although counter intuitive - it is correct)
edited Apr 4 at 11:44
answered Mar 28 at 20:53
KamilKamil
85 bronze badges
85 bronze badges
add a comment
|
add a comment
|
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55400177%2fhibernate-jpa-mappedby-vs-owner-of-the-relation-cascades%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown