JPA:我应该如何注释这个地图集合?
JPA: How should I annotate this Map collections?
我会通过给你一个描述性的例子来解释我自己。假设我们正在使用 JPA 编写一个非常简单的云存储,所以我们有两个主要的 classes,User
和 File
,编码如下:
class User {
List<File> ownFiles;
Map<File, Integer> sharedFiles;
}
class File {
User author;
Map<User, Integer> sharedUsers;
}
我应该如何注释这些字段? 我试过了,但我总是得到 NotSerializableException
"data too long for column".
对了,File
只是一个例子,我真正的class很小,只有一些String组成。所以我很确定 NotSerializableException
是因为地图注释而抛出的。
顺便说一句,这里有地图值的含义,
- 在
User
的情况下,文件的整数值表示用户对文件的权限级别
- 并且在
File
的情况下,密钥是文件共享给的那些用户,值是该用户对 File
的权限级别
P.S:我正在使用 Eclipselink
如评论中所述,JPA 1.0 无法以这种方式处理 Map<>(因此尝试进行序列化)
JPA 2.0 增加注解,毛病多,属性细腻(个人意见)
https://wiki.eclipse.org/EclipseLink/Examples/JPA/2.0/ElementCollections
我并不惊讶生成的数据库可以是相似的
在我看来,我可以使用 JPA 1 方式更好地控制数据库(对我来说更干净)。让我展示一下我的建议。
我对你在1.x哲学中的逻辑结构的清理是:
class User {
// ... fields waht You want
}
class FileEtiquette {
User author;
}
class SharingIncident {
User user;
FileEtiquette file;
int level;
}
可能是我没看懂你的命名法,所以起的名字可能不够优雅。
下次尝试,未编译,仅供示例。
@Entity
class User {
@Id
int id;
@Basic
Set<SharingIncident> shares;
@Basic
Set<FileEtiquette> myFiles;
// ... fields waht You want
}
@Entity
class FileEtiquette {
@Id
int id;
@Basic
Set<SharingIncident> sharedBy;
User author;
}
@Entity
class SharingIncident {
@Id
int id;
User user;
FileEtiquette file;
int level;
}
很少评论。
- 多对多可以用'automagically'的方式实现,但是在你的
整数字段的例子很有趣,值得设计关系
手动。
- 通常当普通程序员认为
List<>
时,在 JPA 中 Set<>
可以
变得更好
- 更改您的
File
名字是我个人的喜好
- 这只是基础,根据我对您的意图的理解,可以进行许多改进。我的目标是展示如何以经典方式替换 Map<>
下一步可能,让我考虑一下
基于this tutorial我按以下方式注释了字段:
class User {
@OneToMany
List<File> ownFiles;
@ElementCollection
Map<File, Integer> sharedFiles;
}
class File {
@ManyToOne
User author;
@ElementCollection
Map<User, Integer> sharedUsers;
}
更详细:
class User {
@OneToMany
@JoinTable(name = "USER_HAS__OWN_FILES", joinColumns = {
@JoinColumn(name = "AUTHOR", referencedColumnName = "USERNAME")},
inverseJoinColumns = {@JoinColumn(name = "OWN_FILE_ID", referencedColumnName = "ID") })
List<File> ownFiles;
@ElementCollection
@CollectionTable(name = "USER_HAS_SHARED_FILES", joinColumns =
@JoinColumn(name = "USERNAME", referencedColumnName = "USERNAME"))
@MapKeyJoinColumn(name = "SHARED_FILE_ID", referencedColumnName = "ID")
@Column(name = "PERMISSION_LEVEL")
Map<File, Integer> sharedFiles;
}
class File {
@ManyToOne
@JoinColumn(name = "FILE_AUTHOR", referencedColumnName = "USERNAME")
User author;
@ElementCollection
@CollectionTable(name = "FILE_HAS_BEEN_SHARED_TO_USER",
joinColumns = @JoinColumn(name = "FILE_ID", referencedColumnName = "ID"))
@MapKeyJoinColumn(name = "USER_THAT_FILE_HAS_BEEN_SHARED_TO", referencedColumnName = "USERNAME")
@Column(name = "PERMISSION_LEVEL")
Map<User, Integer> sharedUsers;
}
现在它按我预期的那样工作,生成了下表:
User (ID, Username, ...)
File (ID, Filename, Author, ...)
User_has_shared_files (Username, Shared_file_id, permission_level)
User_has__own_files (Username, Own_file_id)
File_has_been_shared_to_user (File_id, Username_id, permission_level)
@ElementCollection
注解对映射很有用Java.Map<Entity, basicType>
我会通过给你一个描述性的例子来解释我自己。假设我们正在使用 JPA 编写一个非常简单的云存储,所以我们有两个主要的 classes,User
和 File
,编码如下:
class User {
List<File> ownFiles;
Map<File, Integer> sharedFiles;
}
class File {
User author;
Map<User, Integer> sharedUsers;
}
我应该如何注释这些字段? 我试过了,但我总是得到 NotSerializableException
"data too long for column".
对了,
File
只是一个例子,我真正的class很小,只有一些String组成。所以我很确定NotSerializableException
是因为地图注释而抛出的。顺便说一句,这里有地图值的含义,
- 在
User
的情况下,文件的整数值表示用户对文件的权限级别 - 并且在
File
的情况下,密钥是文件共享给的那些用户,值是该用户对File
的权限级别
- 在
P.S:我正在使用 Eclipselink
如评论中所述,JPA 1.0 无法以这种方式处理 Map<>(因此尝试进行序列化)
JPA 2.0 增加注解,毛病多,属性细腻(个人意见) https://wiki.eclipse.org/EclipseLink/Examples/JPA/2.0/ElementCollections 我并不惊讶生成的数据库可以是相似的
在我看来,我可以使用 JPA 1 方式更好地控制数据库(对我来说更干净)。让我展示一下我的建议。
我对你在1.x哲学中的逻辑结构的清理是:
class User {
// ... fields waht You want
}
class FileEtiquette {
User author;
}
class SharingIncident {
User user;
FileEtiquette file;
int level;
}
可能是我没看懂你的命名法,所以起的名字可能不够优雅。
下次尝试,未编译,仅供示例。
@Entity
class User {
@Id
int id;
@Basic
Set<SharingIncident> shares;
@Basic
Set<FileEtiquette> myFiles;
// ... fields waht You want
}
@Entity
class FileEtiquette {
@Id
int id;
@Basic
Set<SharingIncident> sharedBy;
User author;
}
@Entity
class SharingIncident {
@Id
int id;
User user;
FileEtiquette file;
int level;
}
很少评论。
- 多对多可以用'automagically'的方式实现,但是在你的 整数字段的例子很有趣,值得设计关系 手动。
- 通常当普通程序员认为
List<>
时,在 JPA 中Set<>
可以 变得更好 - 更改您的
File
名字是我个人的喜好 - 这只是基础,根据我对您的意图的理解,可以进行许多改进。我的目标是展示如何以经典方式替换 Map<>
下一步可能,让我考虑一下
基于this tutorial我按以下方式注释了字段:
class User {
@OneToMany
List<File> ownFiles;
@ElementCollection
Map<File, Integer> sharedFiles;
}
class File {
@ManyToOne
User author;
@ElementCollection
Map<User, Integer> sharedUsers;
}
更详细:
class User {
@OneToMany
@JoinTable(name = "USER_HAS__OWN_FILES", joinColumns = {
@JoinColumn(name = "AUTHOR", referencedColumnName = "USERNAME")},
inverseJoinColumns = {@JoinColumn(name = "OWN_FILE_ID", referencedColumnName = "ID") })
List<File> ownFiles;
@ElementCollection
@CollectionTable(name = "USER_HAS_SHARED_FILES", joinColumns =
@JoinColumn(name = "USERNAME", referencedColumnName = "USERNAME"))
@MapKeyJoinColumn(name = "SHARED_FILE_ID", referencedColumnName = "ID")
@Column(name = "PERMISSION_LEVEL")
Map<File, Integer> sharedFiles;
}
class File {
@ManyToOne
@JoinColumn(name = "FILE_AUTHOR", referencedColumnName = "USERNAME")
User author;
@ElementCollection
@CollectionTable(name = "FILE_HAS_BEEN_SHARED_TO_USER",
joinColumns = @JoinColumn(name = "FILE_ID", referencedColumnName = "ID"))
@MapKeyJoinColumn(name = "USER_THAT_FILE_HAS_BEEN_SHARED_TO", referencedColumnName = "USERNAME")
@Column(name = "PERMISSION_LEVEL")
Map<User, Integer> sharedUsers;
}
现在它按我预期的那样工作,生成了下表:
User (ID, Username, ...)
File (ID, Filename, Author, ...)
User_has_shared_files (Username, Shared_file_id, permission_level)
User_has__own_files (Username, Own_file_id)
File_has_been_shared_to_user (File_id, Username_id, permission_level)
@ElementCollection
注解对映射很有用Java.Map<Entity, basicType>