Hibernate Bidirectional @Manytoone, Updating the Not Owning Side Not Working

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



Leave a reply



Submit