Hibernate bidirectional @ManyToOne, updating the not owning side not working
For a consistent domain model you should always set both sides of the relation, like this:
TypeB b = new TypeB();
TypeA a = new TypeA();
a.setBs(ListUtils.createList(b));
b.setA(a);
this.typeBDao.save(b);
this.typeADao.save(a);
When your entities are in an inconsistent state, JPA will always store values according to the object state of the owning side of the JPA relation. In this case TypeB owns the relation to TypeA. Thus if an object of TypeB does not have a reference to TypeA, JPA assumes there is no relation defined.
Bidirectional onetomany doesnt update foriegn key
As Vlad Mihalcea explains in his great article: ...you need to synchronize both end of the bidirectional association.
For your case before session.save(c1);
you should add:
item1.setCart(c1);
item2.setCart(c1);
Or, it's even better to create helper methods in your Cart
class, such as:
public void addItem(Item item) {
items.add(item);
item.setCart(this);
}
public void removeItem(Item item) {
items.remove(item);
item.setCart(null);
}
Why Spring JPA Bidirectional OneToMany and ManyToOne is not updating the foreign key column?
You're missing the @JoinColumn
on the child side:
@Entity
@Table(name = "ms_dealer")
public class Dealer {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "account_account_id")
public Account account;
// other fields
}
You have used mappedBy
on the parent side, but there is no mapping on the child side. You need to indicate, that the Dealer
is the relationship owner - it has the foreign key.
Edit: if you're persisting (not merging) the Account
entity, together with its children, you should not pass ids of child entities. (Actually passing any ids upon persist is a code smell and most probably a performance killer.) The json used should look like:
{
"accountName": "string",
"accountEmail": "string",
"accountAddress": "string",
"town": "string",
"npwp": "string",
"phoneNumber": "string",
"fax": "string",
"remarks": "string",
"entryTime": "2020-04-07T15:01:29.404Z",
"active": true,
"dealer": [
{
"dealerName": "string",
"dealerEmail": "string",
"dealerAddress": "string"
}
]
}
Before saving both-side synchronization might also be needed:
account.getDealer().forEach(d -> d.setAccount(account));
Edit:
From Author
edits must cascade to child:
@OneToMany(mappedBy = "account", cascade = CascadeType.ALL, orphanRemoval = true)
public List<Dealer> dealer;
You might also add @JsonIgnore
over Action
or List<Dealer>
to avoid stackoverflow on serialization to json.
Non-owning entity side of @OneToOne/@ManyToOne/@ManyToMany
In the bi-directional relationship betweens two objects ,you have to choose which sides to manage the relationship. From the database perspective , managing the relationship means managing the value of some FK column that link between two tables. The side that managing it is called owning side. Otherwise, it is call non-owning side.
So back to your example on ProjectManager
and Project
. Which object is the owning side depends on which object you choose to manage their relationship.
If you choose ProjectManager
to be the owning side (hence Project
is the non-owning side), only the values of ProjectManager#getProjects()
will be used to determine the value of such FK column. (i.e. project
table 's project_manager_id
column in this case) The value of Project#getProjectManager()
will be ignored and does not affect the value of this FK column.
In term of JPA mapping , it is :
@Entity
@Table(name="project_manager")
public class ProjectManager{
@OneToMany
private List<Project> projects = new ArrayList<>();
}
@Entity
@Table(name="project")
public class Project {
@ManyToOne
@JoinColumn(name = "project_manager_id")
private ProjectManager projectManager;
}
On the other hands , if you choose Project
to the owning side (hence ProjectManager
is the non-owning side) , only the value of Project#getProjectManager()
will be used to determine the value of this FK column while the value of ProjectManager#getProjects()
will be ignored. The JPA mapping in the case will be :
@Entity
@Table(name="project_manager")
public class ProjectManager{
@OneToMany(mappedBy="projectManager")
private List<Project> projects = new ArrayList<>();
}
@Entity
@Table(name="project")
public class Project {
@ManyToOne
@JoinColumn(name = "project_manager_id")
private ProjectManager projectManager;
}
P.S: I explain it using property access , hopefully you should get the idea.
Update entity from non-owner side in bi-directional many-to-one relationship
The answer is in the question: the owner side of the association is Wheel, and Hibernate will only use the owner side to decide if an association exists or not. You should always update the owner side when updating the non-owner side (and vice-versa, if you want a coherent object graph). The most robust way is to encapsulate it in the Car entity:
public void addWheel(Wheel w) {
this.wheels.add(w);
w.setCar(this);
}
public void removeWheel(Wheel w) {
this.wheels.remove(w);
w.setCar(null);
}
public Set<Wheel> getWheels() {
// to make sure the set isn't modified directly, bypassing the
// addWheel and removeWheel methods
return Collections.unmodifiableSet(wheels);
}
jpa hibernate one-to-many bidirectional
In your bi-directional relationship Tenant
is the owner of the relationship. Since you are persisting Apartment
you have to manually set the apartment of tenant. If you want to get rid of manual setting change your @OneToMany
as follows:
@OneToMany(cascade = CascadeType.ALL)
@JoinColumn(name="ApartmentID",referencedColumnName="ApartmentID")
private List<Tenant> tenants;
By the way, with your current sample if you are persisting tenant with apartment; apartment will be automatically persisted.
How do you save entities with a bidirectional relationship from the non-owning side?
The best solution was to replace the OneToMany
and ManyToOne
with ManyToMany
relationships, and using Node
instead of referencing NodeNode
.
@ManyToMany(fetch = FetchType.EAGER, cascade = { CascadeType.MERGE, CascadeType.REFRESH, CascadeType.DETACH })
@JoinTable(name = "node_node", joinColumns = @JoinColumn(name = "node_id_1"), inverseJoinColumns = @JoinColumn(name = "node_id_2"))
private Set<Node> children;
@ManyToMany(fetch = FetchType.EAGER, mappedBy = "children")
private Set<Node> parents;
Related Topics
How to Run MySQL In-Memory for Junit Test Cases
How to Apply Multiple Predicates to a Java.Util.Stream
How to Use Hibernate @Any-Related Annotations
Why Can't I Use \U000D and \U000A as Cr and Lf in Java
Case Insensitive JSON to Pojo Mapping Without Changing the Pojo
@Valid Annotation Is Not Validating the List of Child Objects
Suppress Deprecated Import Warning in Java
What Is the Use of Pattern.Quote Method
How to Clear Permgen Space Error in Tomcat
Conversion from 12 Hours Time to 24 Hours Time in Java
404 Error Redirect in Spring with Java Config
Generating 8-Character Only Uuids
How to Calculate the Elapsed Time of an Event in Java