我在数据库中有这种关系结构,我无法改变:
------------------------
| Person |
------------------------
id : pk
------------------------
------------------------
| PersonAddress |
------------------------
person_id: pk, fk
address_id: pk, fk
address_type
------------------------
------------------------
| Address |
------------------------
id: pk
------------------------
我正在尝试使用JPA和Hibernate注释配置这些关系。 我尝试过的方法之一就是这个:
@Entity
class Person {
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name = "person_id")
private List<PersonAddress> addresses;
}
@Entity
class PersonAddress {
@ManyToOne
@JoinColumn(nullable = false)
private AddressType type;
@EmbeddedId
private PersonAddressId id;
}
@Embeddable
class PersonAddressId implements Serializable {
@ManyToOne
@JoinColumn(name = "person_id")
private Person person;
@ManyToOne(cascade = CascadeType.ALL)
@MapsId("id")
@JoinColumn(name = "address_id", nullable = false)
private Address address;
}
@Entity
public class Address {
@Id
@GeneratedValue
@Column(name = "address_id")
private Long id;
}
当我做repository.save(person)
时。我希望更改会级联到地址。
问题是,当我尝试保存时,我得到NullPointerException。调试时我发现,Hibernate试图保存PersonAddress对象,它需要使用其中一个主键的哈希码。
由于Address尚未保存,因此它具有id == null。目前基本上是保存流程:
Person -> PersonAddress -> Address
但它应该是:
Person -> Address -> PersonAddress
(因为它需要为person和adddress生成id)。
有没有办法让Hibernate以这种方式运行?
答案 0 :(得分:0)
你的hashCode方法实现错误。您必须始终检查null,因为可以在各种情况下调用此方法。
详细了解该主题:https://vladmihalcea.com/how-to-implement-equals-and-hashcode-using-the-jpa-entity-identifier/
答案 1 :(得分:0)
发现问题所在。为主键使用创建@Embeddable
类时,需要为id列提供简单对象。即它不应包含由外键映射的对象:
@Embeddable
class PersonAddressId implements Serializable {
@Column(nullable = false)
private Long relatedPartyId;
@Column(nul
private Long addressId;
}
要支持复合主键以及外键,您需要添加@MapsId
注释:
@Entity
public class Person Address {
@ManyToOne
@MapsId("personId")
@JoinColumn(name = "person_id", nullable = false, updatable = false)
private RelatedParty relatedParty;
@EmbeddedId
@JsonIgnore
private RelatedPartyAddressId id;
@ManyToOne
@MapsId("addressId")
@JoinColumn(name = "address_id", nullable = false)
private Address address;
}