如何在休眠中建立友谊关系?
How to model a friendship relationship in hibernate?
我需要一段友情关系。我有一个友谊 class,有两个主键,每个主键都是一个成员 class。我收到以下异常:
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;
您必须将单独的 ID 字段添加到 Member
class,以便 @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;
}
在 Friendship
class 中也尝试指定 @JoinColumn:
@Entity
public class Friendship implements Serializable {
@Id
@ManyToOne
@JoinColumn(name = "username")
Member requester;
...
}
您缺少 Friendship
class 中主键的建模。
例如:
@Embeddable
public class FriendshipPK implements Serializable
{
@Column(name = "requester_id")
protected String requesterId;
@Column(name = "friend_id")
protected String friendId;
}
友情class现在可以修改如下:
@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;
}
我稍微更新了会员class:
@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;
}
我从成员 class 中删除了级联,并首先创建了凭据对象。但您可以根据需要更改它。
撇开 Member
和 Credential
应该实现 Serializable
如果使用多个没有标识符类型的 id 属性,你的映射很好,这似乎是 Hibernate 中的一个错误.
解决方案 1
我设法通过在 friend
中声明 referencedColumnName
和在 Friendship
中声明 requester
关联来完成这项工作:
@Id
@ManyToOne
@JoinColumn(referencedColumnName = "username")
Member requester;
@Id
@ManyToOne
@JoinColumn(referencedColumnName = "username")
Member friend;
这样我们明确地告诉 Hibernate 复合 id 引用了哪些列,这样它就不必自己弄清楚了。
解决方案 2
解决方案1让我想到了Hibernate中的错误可能是什么原因。它似乎在某种程度上受到 Hibernate 处理实体映射的顺序的影响。如果您显式声明引用列,则一切正常,否则 Hibernate 在构建复合键时似乎不知道有关引用列的所有详细信息。
所以我将添加注释 classes 到会话工厂配置的顺序更改为:
Credential
Member
Friendship
然后一切都与您的原始映射一起工作(在 Member
和 Credential
中实施 Serializable
之后)。
我按此顺序以编程方式将 classes 添加到 Configuration
class,但我认为通过在 persistence.xml
中指定此顺序可以实现相同的效果] 或 hibernate.cfg.xml
:
<class>Credential</class>
<class>Member</class>
<class>Friendship</class>
尽管如此,此解决方案仅用于演示目的(您或其他人稍后可以重新排序 classes 而无需牢记此问题),因此我建议使用解决方案 1。
备注
您更了解您的用例,但我个人认为您应该使用 @IdClass
或 @EmbeddedId
,因为它们在 JPA 中已标准化;没有标识符类型的多个 id 属性是 Hibernate 特定的功能。除了能够更轻松地构建用于搜索和查询相应实体的主键对象外,专用 PK 对象通常更轻巧,并且在序列化时提供更好的性能,尤其是在启用二级缓存的情况下。
我需要一段友情关系。我有一个友谊 class,有两个主键,每个主键都是一个成员 class。我收到以下异常:
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;
您必须将单独的 ID 字段添加到 Member
class,以便 @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;
}
在 Friendship
class 中也尝试指定 @JoinColumn:
@Entity
public class Friendship implements Serializable {
@Id
@ManyToOne
@JoinColumn(name = "username")
Member requester;
...
}
您缺少 Friendship
class 中主键的建模。
例如:
@Embeddable
public class FriendshipPK implements Serializable
{
@Column(name = "requester_id")
protected String requesterId;
@Column(name = "friend_id")
protected String friendId;
}
友情class现在可以修改如下:
@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;
}
我稍微更新了会员class:
@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;
}
我从成员 class 中删除了级联,并首先创建了凭据对象。但您可以根据需要更改它。
撇开 Member
和 Credential
应该实现 Serializable
如果使用多个没有标识符类型的 id 属性,你的映射很好,这似乎是 Hibernate 中的一个错误.
解决方案 1
我设法通过在 friend
中声明 referencedColumnName
和在 Friendship
中声明 requester
关联来完成这项工作:
@Id
@ManyToOne
@JoinColumn(referencedColumnName = "username")
Member requester;
@Id
@ManyToOne
@JoinColumn(referencedColumnName = "username")
Member friend;
这样我们明确地告诉 Hibernate 复合 id 引用了哪些列,这样它就不必自己弄清楚了。
解决方案 2
解决方案1让我想到了Hibernate中的错误可能是什么原因。它似乎在某种程度上受到 Hibernate 处理实体映射的顺序的影响。如果您显式声明引用列,则一切正常,否则 Hibernate 在构建复合键时似乎不知道有关引用列的所有详细信息。
所以我将添加注释 classes 到会话工厂配置的顺序更改为:
Credential
Member
Friendship
然后一切都与您的原始映射一起工作(在 Member
和 Credential
中实施 Serializable
之后)。
我按此顺序以编程方式将 classes 添加到 Configuration
class,但我认为通过在 persistence.xml
中指定此顺序可以实现相同的效果] 或 hibernate.cfg.xml
:
<class>Credential</class>
<class>Member</class>
<class>Friendship</class>
尽管如此,此解决方案仅用于演示目的(您或其他人稍后可以重新排序 classes 而无需牢记此问题),因此我建议使用解决方案 1。
备注
您更了解您的用例,但我个人认为您应该使用 @IdClass
或 @EmbeddedId
,因为它们在 JPA 中已标准化;没有标识符类型的多个 id 属性是 Hibernate 特定的功能。除了能够更轻松地构建用于搜索和查询相应实体的主键对象外,专用 PK 对象通常更轻巧,并且在序列化时提供更好的性能,尤其是在启用二级缓存的情况下。