I want to make a relation between 2 models by User.id
and Address.user_id
columns.
I have created two tables with One-To-One relations:
@Entity() @Table(name = "user") public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; @OneToOne(cascade = CascadeType.ALL) @JoinColumn(name = "id", referencedColumnName = "user_id") private Address address; public int getId() { return id; } public void setId(Integer id) { this.id = id; } public Address getAddress() { return address; } public void setAddress(Address address) { this.address = address; } } @Entity @Table(name = "address") public class Address extends com.mezoline.domain.common.Entity { @Id @GeneratedValue private int id; @OneToOne(mappedBy = "address") private User user; public int getId() { return id; } public void setId(int id) { this.id = id; } public User getUser() { return user; } public void setUser(User user) { this.user = user; } }
Here I can already see the problem: hibernate did not generate database column Address.user_id
how I expected.
I create Address
instance and add that to User
:
User user = entityManager.find(User.class, 69); Address address = new Address(); address.setCity("Тест"); userTransaction.begin(); user.setAddress(address); entityManager.merge(user); userTransaction.commit();
After I call merge(user)
. Data success saved… without any relation info.
UPD:
With config below, JPA will create relation column Address.user_id
(just relation owner was swapped)
public class User { ... @OneToOne(cascade = CascadeType.ALL, mappedBy = "user") private Address address; ... } public class Address { .... @OneToOne() @JoinColumn(name = "user_id") private User user; .... }
But after save Address.user_id
is null… (other columns are being filled)
UPD2:
Thanks. Second config work fine, when was set the inverse side relation field (as suggested in the comments):
Address address = createAddress(); address.setUser(user); user.setAddress(address);
But I don`t understand, why first config (where the User is the owning side) don`t work.
Answer
That’s because there is a logical error in your expectations about the initial config.
You declared User
to be the owning side of the relationship. Owning means the foreign key representing the relationship will be kept in the USER
table, not in the Address
table.
At the same time, you annotated User.address
with @JoinColumn(name = "id", referencedColumnName = "user_id")
. Basically, I think you’re trying to force the ADRESS
table to hold the foreign key. But in that case, Adress
should be the owning side.
If you want the initial config to work, all you should do is you should replace the current JoinColumn
annotation with @JoinColumn(name = "address_id")
. The foreign key will end up in the USER
table. When persisting the entities, User.address
must be set; setting Address.user
is optional.
If you absolutely need to have the key in the ADDRESS
table, make the Address
table the owning side (you will then only have to ensure Address.user
is set at persist time; however, you will still want the User.address
to be set in order for the cascade to work, unless you persist the Address
entity explicitly).