JPA,Hibernate我可以做复合主键,其中一个元素是外国kay @OneToMany?

时间:2015-06-08 20:47:48

标签: hibernate jpa foreign-keys entity composite-primary-key

我希望在我的实体中包含由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

extentions of previous example

2 个答案:

答案 0 :(得分:4)

摆脱providerId字段及其相应的getter和setter。将@Id注释添加到getProvider()。像这样定义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中,属性类型必须与Id的{​​{1}}属性的类型匹配。

这在JPA 2.1规范第2.4.1节中讨论。

更新2的建议:

Provider

注意属性名称必须匹配(即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的{​​{1}}匹配(即Entity)。

我使用了字段注释,但您可以将它们转换为属性注释。

同样:JPA 2.1规范在2.4.1.3节中只有这种关系的一个例子。

答案 1 :(得分:0)

执行复合主键的最佳方法是使用@EmbeddedId和相应的@Embeddable类。

在我们的400多个数据库实体中,大约135个使用嵌入式ID类来实现复合(多字段)主键。

这里有很多关于SO的问题和答案,并举例说明。