两个外键作为主键

Posted

技术标签:

【中文标题】两个外键作为主键【英文标题】:Two foreign keys as primary key 【发布时间】:2015-09-22 09:20:02 【问题描述】:

如何使用 hibernate 注释实现以下表格?

当前代码是:(为简洁起见)

用户

@Entity
@Table(name = "user")
public class User implements java.io.Serializable 
    @Id
    @GeneratedValue
    public Long getId() 
        return id;
    

社交网络

@Entity
@Table(name = "social_network")
public class SocialNetwork implements java.io.Serializable 
    @Id
    @GeneratedValue
    public int getId() 
        return id;
    

社交档案

@Entity
@Table(name = "social_profile")
public class SocialProfile implements java.io.Serializable 
    @Id
    @ManyToOne
    @JoinColumn(name="user_id")
    public User getUser() 
        return user;
    

    @Id
    @ManyToOne
    @JoinColumn(name="social_network_id")
    public SocialNetwork getSocialNetwork() 
        return socialNetwork;
    

显然我的代码现在不能正常工作。任何人都可以对此有所了解吗?

【问题讨论】:

您也可以考虑为您的 social_profile 添加一个简单的 ID 列,并在两个 FK 上一起添加一个唯一约束。它几乎相同,但更容易处理,恕我直言 @stg 感谢您的提示,我在 social_profile 表中添加了一个 id,并且我使这些字段独一无二且不为空。这种方式简单得多。 【参考方案1】:

您需要一个像这样的可嵌入 SocialProfileId:

@Embeddable
public class SocialProfileId implements Serializable 
    @Column(name = "user_id")
    private long userId;
    @Column(name = "social_network_id")
    private long socialNetworkId;

然后,您的 SocialProfile 实体将如下所示:

@Entity
@Table(name = "social_profile")
public class SocialProfile implements java.io.Serializable 

    @EmbeddedId
    private SocialProfileId id;

    @ManyToOne
    @JoinColumn(name="user_id")
    public User getUser() 
        return user;
    

    @ManyToOne
    @JoinColumn(name="social_network_id")
    public SocialNetwork getSocialNetwork() 
        return socialNetwork;
    

编辑抱歉,我在回答中的字段和方法上混杂了注释......永远不要那样做! ;-)

【讨论】:

感谢您的信息。我会接受这一点,但我决定使用上面 cmets 中建议的 stg 之类的代理键,这会使事情变得更简单。 是的,有一个简单的 id 更简单......我刚刚在这里回答了你的问题 ;-)【参考方案2】:

您似乎需要具有带有额外列的连接表的mamy-to-many 映射。 为此,您需要再创建 2 个类。

仅供参考:http://www.mkyong.com/hibernate/hibernate-many-to-many-example-join-table-extra-column-annotation/

【讨论】:

【参考方案3】:

我在 REST 应用程序中遇到的问题与此类似,但略有不同,我将在此处发布。 我有 2 个数据表:SongTag,每个都有一个 id(songid、tagid)。 然后我有一个表用于将它们连接在一起 Tagassignment,它只有 SongTag 的主键。所以我不想加入他们,我想保留两个外键的表。

我的解决方案来源:http://www.objectdb.com/java/jpa/entity/id


之前

歌曲

@Entity
@Table(name = "songs")
data class Song(

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    val id: Int,

    ...
)

标签

@Entity
@Table(name = "tags")
data class Tag(

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    val id: Int,

    ...
)

标签分配

 @Entity
 @Table(name = "tagassignment")
 data class Tagassignment(

     val songid: Int,

     val tagid: Int

 )

之后

我没有更改歌曲标签

标签分配

@Entity
@IdClass(value = TagassignmentKey::class)
@Table(name = "tagassignment")
data class Tagassignment(

    @Id
    val songid: Int,

    @Id
    val tagid: Int

)

我创建了一个 Key 类

标签分配键

class TagassignmentKey(val songid: Int, val tagid: Int) : Serializable 

    constructor() : this(0, 0)


【讨论】:

【参考方案4】:

除了 Pras 所说的之外,我们甚至可以将 @ManyToOne 移动到 @Embeddable 类本身中,这样 SocialProfileId 就会看起来像这样,您可以在 Embedded 类本身中清楚地看到它引用了另一个表

@Embeddable
public class SocialProfileId implements Serializable 

    @ManyToOne
    @JoinColumn(name = "user_id")
    private User userId;


    @ManyToOne
    @JoinColumn(name = "social_network_id")
    private SocialNetwork socialNetworkId;

    public SocialProfileId(User userId, SocialNetwork socialNetworkId) 
        this.userId = userId;
        this.socialNetworkId = socialNetworkId;
    


您的 SocialProfile 实体可以简单地具有嵌入式类和其他字段,如电子邮件等..

@Entity
@Table(name = "social_profile")
public class SocialProfile implements java.io.Serializable 

    @EmbeddedId
    private SocialProfileId id;

    @Column(name="email")
    private String email;

【讨论】:

以上是关于两个外键作为主键的主要内容,如果未能解决你的问题,请参考以下文章

POSTGRESQL外键引用两个不同表的主键

oracle 表一的A、B两个字段是联合主键,表二使用表一的A字段作为外键,这样可以吗?

Symfony/Doctrine 类表继承和外键作为主键

数据库中主键和外键是干嘛用的?

数据库中主键和外键是干嘛用的?

MyBatis - 关联查询