当前位置: 首页 > 知识库问答 >
问题:

JPA,Hibernate我可以做复合主键吗?哪一个元素是foreign kay@OneToMany?

薛宜
2023-03-14

我希望在我的实体中有一个由两列(属性)组成的复合主键,同时有一列是外键。

我写了这样的东西,但不知道它是否有效,因为外键在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

共有2个答案

梁丘凯定
2023-03-14

制作复合主键的最佳方式是将@EmbeddedId与相应的< code > @ embedded 类一起使用。

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

SO上有很多问题和答案,并附有这些示例。

华振
2023-03-14

去掉< code>providerId字段及其对应的getter和setter。将< code>@Id批注添加到< code>getProvider()中。如下定义< code>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(即提供程序)中的属性名称匹配,但属性的类型不同。在IdClass中,属性类型必须与ProviderId属性的类型匹配。

这在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属性的类型必须匹配引用的EntityIdClass(即ServicePointId)。

我使用过字段批注,但您可以将这些批注转换为属性批注。

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

 类似资料:
  • 在我的jpa映射中,我试图将带有一个主键的父类映射到带有复合键的子类,但似乎插入了错误的表,它已经生成了2个表,但不幸的是我没有绑定外键(policy_value_summary_id) 我试图用策略值(子类)保存策略摘要值(父),如下所示 下面是输出给我的错误

  • 我有一个复合主键,其中一个键为空。实体中必须存在哪些注释,以便我可以使用此类JPA获取数据: 我尝试使用IdClass Annotation和EmbeddedId Annotation,但出现异常: 例如,使用了数据,但在实际项目中使用了类似的数据,因此无法用值替换null。

  • 问题内容: 我的JPA模型中有以下类(省略了getters,setters和无关字段): 我需要定义一个类,使得当从所述类生成DDL时,相应的表的主键被由密钥和。我尝试了以下方法: 但这会为表生成以下内容: 请注意,和都是可为空的,当我尝试将DDL加载到SQL Server时会导致以下错误 无法在表“ PRICE”中的可为空的列上定义PRIMARY KEY约束 我不明白为什么这些可以为空,因为在域

  • 我在使用复合主键的hibernate实体集时遇到了问题。 我们的应用程序中有一个概念“Target”。目标id应该是其他三个表(实体)主id的组合。目标也有一个int标记。员工应该有一系列目标。SQL如下所示: 这个SQL工作正常,它允许我每个role_id(员工)多个目标,只要应用程序和项目分类不同。 这是目标ID类 这是目标类 这是employee类,我想在其中为每个员工存储一组目标。 通过h

  • 问题内容: 我在玩redis,想重新创建我在mysql中拥有的表。这是我用来创建它的mysql命令: 我的数据基本上是两列,每一列都有彼此唯一的数字,例如: 当我在redis上玩耍并尝试创建上述数据时,“ 3”键只会不断被我输入的最后一个值取代。有没有办法使该版本在Redis中工作? 问题答案: 使用Redis更好地表示您的数据的模型是使用value1对象的简单集合(每个key1对象一个)。按照示

  • 我的数据库是: 我们可以在Table2中为Table1中的1设置多行。 我的TABLE1实体是: 我的Table1Id类是: 我的TABLE2实体是: 我的Table2Id类是: 当我尝试启动我的tomcat时,我有以下错误: 我尝试使用引用列,主键连接列和许多其他东西,但是通过在互联网上阅读它,它可以解决数据库建模问题。我认为问题是主键和外键在2个表中具有相同的名称,但我可能是错的......我