JPA,Hibernate 我可以做复合主键,其中一个元素是外键@OneToMany?
JPA, Hibernate can I do composite primary key which one element is foreign kay @OneToMany?
我想在我的实体中包含由 2 列(属性)组成的复合主键,并且其中之一同时作为外键。
我写了这样的东西,但不知道它是否有效,因为外键在 IntelliJ 数据源中被标记为生成的值
@Entity
@Table(name = "service_point")
@Access(AccessType.PROPERTY)
@IdClass(ServicePointId.class)
public class ServicePoint {
private Long providerId;
private Integer servicePointNumber;
private Provider provider;
@Id
@Basic(optional = false)
@Column(name = "provider_id", nullable = false, insertable = false,
updatable = false, columnDefinition = "BIGINT UNSIGNED")
public Long getProviderId() {
return providerId;
}
public void setProviderId(Long providerId) {
this.providerId = providerId;
}
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Basic(optional = false)
@Column(name = "service_point_no", nullable = false, columnDefinition = "BIGINT UNSIGNED")
public Integer getServicePointNumber() {
return servicePointNumber;
}
public void setServicePointNumber(Integer servicePointNumber) {
this.servicePointNumber = servicePointNumber;
}
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "provider_id")
public Provider getProvider() {
return provider;
}
public void setProvider(Provider provider) {
this.provider = provider;
}
}
更新:
我测试了 Brian Vosburgh 并且有效:
transaction.begin();
em.persist(provider);
ServicePoint servicePoint = new ServicePoint(provider, 1);
em.persist(servicePoint);
transaction.commit();
ServicePoint servicePoint2 = em.find(ServicePoint.class,
new ServicePointId(provider.getUserId(), servicePoint.getServicePointNumber()));
assertTrue("Service point provider id and Provider provider id should be the same.",
servicePoint2.getProvider().getUserId() == provider.getUserId());
assertNotNull("Service point number can not be null", servicePoint2.getServicePointNumber());
assertEquals(servicePoint2.getProvider(), provider);
transaction.begin();
em.remove(servicePoint);
em.remove(provider);
transaction.commit();
更新 2 - 下一个关系复合 PK(3 列)中的新问题,其中 2 个是复合 FK
我一直在尝试类似于下面的解决方案,但无法通过
如何写 ServicePointPhotoId @IdClass
做复合主键的最好方法是使用 @EmbeddedId 和相应的 @Embeddable
class.
在我们的 400 多个数据库实体中,大约 135 个使用嵌入式 ID classes 来实现复合(多字段)主键。
这里有很多关于 SO 的问题和答案以及这些示例。
删除 providerId
字段及其对应的 getter 和 setter。向 getProvider()
添加 @Id
注释。像这样定义 IdClass
:
public class ServicePointId {
private Long provider;
private Integer servicePointNumber;
public Integer getProvider() {
return provider;
}
public void setProvider(Integer provider) {
this.provider = provider;
}
public Integer getServicePointNumber() {
return servicePointNumber;
}
public void setServicePointNumber(Integer servicePointNumber) {
this.servicePointNumber = servicePointNumber;
}
}
请注意 IdClass
中的 属性 名称与 Entity
中的 属性 名称匹配(即 provider
),但属性的类型是不同的。在 IdClass
中,属性 类型必须与 Provider
的 属性 类型匹配。
这在 JPA 2.1 规范的第 2.4.1 节中进行了讨论。
更新 2 的建议:
public class ServicePointPhotoId {
public ServicePointId servicePoint;
public Long photoId;
}
@Entity
@IdClass(ServicePointPhotoId.class)
@Table(name="service_point_photo")
public class ServicePointPhoto {
@Id
@ManyToOne
@JoinColumns({
@JoinColumn(name="provider_id", referencedColumnName="provider_id"),
@JoinColumn(name="service_point_no", referencedColumnName="service_point_no")
})
private ServicePoint servicePoint;
@Id
@Column(name="photo_id")
private Long photoId;
}
注意属性名称必须匹配(即servicePoint
);但是 IdClass
属性的类型必须与引用的 Entity
的 IdClass
匹配(即 ServicePointId
)。
我使用了字段注释,但您可以将它们转换为 属性 注释。
同样:JPA 2.1 规范在第 2.4.1.3 节中有一个这种关系的示例。
我想在我的实体中包含由 2 列(属性)组成的复合主键,并且其中之一同时作为外键。
我写了这样的东西,但不知道它是否有效,因为外键在 IntelliJ 数据源中被标记为生成的值
@Entity
@Table(name = "service_point")
@Access(AccessType.PROPERTY)
@IdClass(ServicePointId.class)
public class ServicePoint {
private Long providerId;
private Integer servicePointNumber;
private Provider provider;
@Id
@Basic(optional = false)
@Column(name = "provider_id", nullable = false, insertable = false,
updatable = false, columnDefinition = "BIGINT UNSIGNED")
public Long getProviderId() {
return providerId;
}
public void setProviderId(Long providerId) {
this.providerId = providerId;
}
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Basic(optional = false)
@Column(name = "service_point_no", nullable = false, columnDefinition = "BIGINT UNSIGNED")
public Integer getServicePointNumber() {
return servicePointNumber;
}
public void setServicePointNumber(Integer servicePointNumber) {
this.servicePointNumber = servicePointNumber;
}
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "provider_id")
public Provider getProvider() {
return provider;
}
public void setProvider(Provider provider) {
this.provider = provider;
}
}
更新:
我测试了 Brian Vosburgh 并且有效:
transaction.begin();
em.persist(provider);
ServicePoint servicePoint = new ServicePoint(provider, 1);
em.persist(servicePoint);
transaction.commit();
ServicePoint servicePoint2 = em.find(ServicePoint.class,
new ServicePointId(provider.getUserId(), servicePoint.getServicePointNumber()));
assertTrue("Service point provider id and Provider provider id should be the same.",
servicePoint2.getProvider().getUserId() == provider.getUserId());
assertNotNull("Service point number can not be null", servicePoint2.getServicePointNumber());
assertEquals(servicePoint2.getProvider(), provider);
transaction.begin();
em.remove(servicePoint);
em.remove(provider);
transaction.commit();
更新 2 - 下一个关系复合 PK(3 列)中的新问题,其中 2 个是复合 FK 我一直在尝试类似于下面的解决方案,但无法通过 如何写 ServicePointPhotoId @IdClass
做复合主键的最好方法是使用 @EmbeddedId 和相应的 @Embeddable
class.
在我们的 400 多个数据库实体中,大约 135 个使用嵌入式 ID classes 来实现复合(多字段)主键。
这里有很多关于 SO 的问题和答案以及这些示例。
删除 providerId
字段及其对应的 getter 和 setter。向 getProvider()
添加 @Id
注释。像这样定义 IdClass
:
public class ServicePointId {
private Long provider;
private Integer servicePointNumber;
public Integer getProvider() {
return provider;
}
public void setProvider(Integer provider) {
this.provider = provider;
}
public Integer getServicePointNumber() {
return servicePointNumber;
}
public void setServicePointNumber(Integer servicePointNumber) {
this.servicePointNumber = servicePointNumber;
}
}
请注意 IdClass
中的 属性 名称与 Entity
中的 属性 名称匹配(即 provider
),但属性的类型是不同的。在 IdClass
中,属性 类型必须与 Provider
的 属性 类型匹配。
这在 JPA 2.1 规范的第 2.4.1 节中进行了讨论。
更新 2 的建议:
public class ServicePointPhotoId {
public ServicePointId servicePoint;
public Long photoId;
}
@Entity
@IdClass(ServicePointPhotoId.class)
@Table(name="service_point_photo")
public class ServicePointPhoto {
@Id
@ManyToOne
@JoinColumns({
@JoinColumn(name="provider_id", referencedColumnName="provider_id"),
@JoinColumn(name="service_point_no", referencedColumnName="service_point_no")
})
private ServicePoint servicePoint;
@Id
@Column(name="photo_id")
private Long photoId;
}
注意属性名称必须匹配(即servicePoint
);但是 IdClass
属性的类型必须与引用的 Entity
的 IdClass
匹配(即 ServicePointId
)。
我使用了字段注释,但您可以将它们转换为 属性 注释。
同样:JPA 2.1 规范在第 2.4.1.3 节中有一个这种关系的示例。