如何在hibernate中建立友谊关系?

时间:2015-06-28 11:38:55

标签: java hibernate jpa orm hibernate-mapping

我需要建立友谊关系。我有一个友谊类,有两个主键,每个主键都是一个成员类。我收到以下例外:

org.hibernate.MappingException: Foreign key (FK_8ynretl1yt1xe3gcvfytrvpq:Friendship [])) must have same number of columns as the referenced primary key (Member [username])

友谊

@Entity
public class Friendship implements Serializable {
    /**
     * 
     */
    private static final long serialVersionUID = -1234656876554786549L;
    @Id
    @ManyToOne
    Member requester;
    @Id
    @ManyToOne
    Member friend;
    @Temporal(javax.persistence.TemporalType.DATE)
Date date;

会员

@Entity
public class Member {
    @Id
    @MapsId
    @OneToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "username")
    Credential credential;
    @Column(nullable = false)
    String fname;
    @Column(nullable = false)
    String lname;
    @Column(nullable = false)
    short gender;

凭据

@Entity
public class Credential {
    @Id
    @Column(nullable = false, unique = true)
    private String username;
    @Column(nullable = false)
    private String password;
    @Column(nullable = false)
    private String authority;
    @Column(nullable = false)
    private boolean enabled;

4 个答案:

答案 0 :(得分:1)

您必须在Member类中添加单独的ID字段,以便映射@MapsID注释。像这样:

@Entity
public class Member implements Serializable {
    @Id
    private String username;

    @MapsId
    @OneToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "username")
    Credential credential;
    @Column(nullable = false)
    String fname;
    @Column(nullable = false)
    String lname;
    @Column(nullable = false)
    short gender;

}

答案 1 :(得分:1)

如果使用不带标识符类型的多个id属性,那么MemberCredential应该实现Serializable,你的映射是好的,这似乎是Hibernate中的一个错误。< / p>

解决方案1 ​​

我设法通过在referencedColumnNamefriendrequester Friendship中声明@Id @ManyToOne @JoinColumn(referencedColumnName = "username") Member requester; @Id @ManyToOne @JoinColumn(referencedColumnName = "username") Member friend; 来完成这项工作:

Credential
Member
Friendship

这样我们就可以明确地告诉Hibernate复合id引用了哪些列,这样它就不必自己弄清楚了。

解决方案2

解决方案1让我想到了Hibernate中可能导致错误的原因。它似乎受到Hibernate处理实体映射的顺序的某种影响。如果您显式声明了引用的列,那么一切正常,否则看起来Hibernate在构建复合键时不知道有关引用列的所有细节。

因此,我将添加带注释的类的顺序更改为会话工厂配置:

Serializable

然后一切都与原始映射一起使用(在MemberCredential中实施Configuration之后。

我已按编程方式将这些类添加到persistence.xml类,但我认为通过在hibernate.cfg.xml<class>Credential</class> <class>Member</class> <class>Friendship</class> 中指定此顺序可以实现相同的效果:

@IdClass

尽管如此,此解决方案仅用于演示目的(您或其他人可以在以后重新排序类而不考虑此问题),因此我建议使用解决方案1.

注意

您更了解您的用例,但我个人认为您应该使用@EmbeddedIdloader.execute(); ,因为它们在JPA中已标准化;不带标识符类型的多个id属性是Hibernate特有的功能。除了能够更容易地构造用于搜索和查询相应实体的主键对象之外,专用PK对象通常更轻,并且在序列化时提供更好的性能,尤其是在启用了二级缓存时。

答案 2 :(得分:0)

Friendship课程中,请尝试指定@JoinColumn

@Entity
public class Friendship implements Serializable {

    @Id
    @ManyToOne
    @JoinColumn(name = "username")
    Member requester;

    ...
}

答案 3 :(得分:0)

您错过了Friendship课程中主键的建模。 例如:

@Embeddable
public class FriendshipPK implements Serializable
{
    @Column(name = "requester_id")
    protected String requesterId;

    @Column(name = "friend_id")
    protected String friendId;
}

现在可以按如下方式修改友谊课程:

@Entity
public class Friendship implements Serializable
{
    @EmbeddedId
    protected FriendshipPK friendshipId = new FriendshipPK();

    @ManyToOne
    @MapsId("requesterId")
    Member requester;

    @ManyToOne
    @MapsId("friendId")
    Member friend;

    @Temporal(javax.persistence.TemporalType.DATE)
    Date date;
}

我稍微更新了会员班:

@Entity
public class Member implements Serializable
{
    @Id
    protected String memberId;

    @MapsId
    @OneToOne(optional = false)
    @JoinColumn(name = "username")
    Credential credential;
    @Column(nullable = false)
    String fname;
    @Column(nullable = false)
    String lname;
    @Column(nullable = false)
    short gender;
}

我从Member类中删除了级联,并首先创建了凭证对象。但是你可以改变这一点。