JPA:我应该如何注释这个地图集合?

JPA: How should I annotate this Map collections?

我会通过给你一个描述性的例子来解释我自己。假设我们正在使用 JPA 编写一个非常简单的云存储,所以我们有两个主要的 classes,UserFile,编码如下:

class User {
       List<File> ownFiles;
       Map<File, Integer> sharedFiles; 
}

class File {
       User author;
       Map<User, Integer> sharedUsers;
}

我应该如何注释这些字段? 我试过了,但我总是得到 NotSerializableException "data too long for column".

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>