连接 3 个表 Hibernate 和 JPA

Moa*_*did 4 sql spring hibernate jpa spring-data

我有三张桌子,我想加入它们,这让我发疯。

表:任务 项目 用户

它们之间都具有多对多关系:就像项目有多个用户,反之亦然,任务有多个用户,反之亦然,项目和用户也是如此。

我正在尝试找到一种在 JPA 和 Hibernate 中实现这一点的方法,我有 2 个选择: ** 1 ** 像这样加入 3 个实体:

项目:

   @ManyToMany(fetch = FetchType.EAGER, 
    cascade =
    {
            CascadeType.DETACH,
            CascadeType.MERGE,
            CascadeType.REFRESH,
            CascadeType.PERSIST
    },
    targetEntity = User.class)
  @JoinTable(name = "Collaborators", 
           joinColumns = @JoinColumn(name = "ProjectFk", referencedColumnName = "id", updatable=false, nullable=false), 
           inverseJoinColumns = @JoinColumn(name = "UserFk", referencedColumnName = "id", updatable=false, nullable=false))
  private Set<User> users = new HashSet<>();
Run Code Online (Sandbox Code Playgroud)

用户:

    @ManyToMany(fetch = FetchType.EAGER, 
            cascade =
                {
                        CascadeType.DETACH,
                        CascadeType.MERGE,
                        CascadeType.REFRESH,
                        CascadeType.PERSIST
                },
                targetEntity = Project.class)
    @JoinTable(name = "Collaborators", 
           joinColumns = @JoinColumn(name = "UserFk", referencedColumnName = "id", updatable=false, nullable=false), 
           inverseJoinColumns = @JoinColumn(name = "ProjectFk", referencedColumnName = "id", updatable=false, nullable=false))
    private Set<Project> projects = new HashSet<>();
Run Code Online (Sandbox Code Playgroud)

任务:

    @ManyToMany(fetch = FetchType.EAGER, 
        cascade =
        {
                CascadeType.DETACH,
                CascadeType.MERGE,
                CascadeType.REFRESH,
                CascadeType.PERSIST
        },
        targetEntity = User.class)
    @JoinTable(name = "Collaborators", 
       joinColumns = @JoinColumn(name = "TaskFk", referencedColumnName = "id", updatable=false, nullable=false), 
       inverseJoinColumns = @JoinColumn(name = "ProjectFk", referencedColumnName = "id", updatable=false, nullable=false))
    @MapKeyJoinColumn(name = "User_id")
    @ElementCollection
    private Map<Project, User> projectUserMap = new HashMap<>();
Run Code Online (Sandbox Code Playgroud)

但这里似乎不起作用

2:创建第四个实体并将其命名为Collaborator,然后尝试找到实现此 SQL 查询的方法:

select * from (
select user.id, Project.id, Task.id
inner join Project on user.join_key = Project.join_key
inner join  Task  on task.join_key = = Project.join_key
) collaborator
Run Code Online (Sandbox Code Playgroud)

任何帮助将不胜感激。谢谢。

tha*_*ngo 5

应该像下面这样实现:

项目类

 @Entity
public class Project extends ABaseEntity{

private Set<User> users = new HashSet<>();

@ManyToMany
@JoinTable(name = "Collaborators",
        joinColumns = @JoinColumn(name = "Project_ID", referencedColumnName = "id", updatable=false, nullable=false),
        inverseJoinColumns = @JoinColumn(name = "User_ID", referencedColumnName = "id", updatable=false, nullable=false))
public Set<User> getUsers() {
    return users;
}

public void setUsers(Set<User> users) {
    this.users = users;
}
}
Run Code Online (Sandbox Code Playgroud)

用户等级

@Entity
@Table(name = "EMA_USER")
public class User extends ABaseEntity {

private Set<Project> projects = new HashSet<>();


@ManyToMany(fetch = FetchType.EAGER,
        cascade = CascadeType.ALL,
        targetEntity = Project.class)
@JoinTable(name = "Collaborators",
        joinColumns = @JoinColumn(name = "User_ID", referencedColumnName = "id", updatable = false, nullable = false),
        inverseJoinColumns = @JoinColumn(name = "Project_ID", referencedColumnName = "id", updatable = false, nullable = false))
public Set<Project> getProjects() {
    return projects;
}

public void setProjects(Set<Project> projects) {
    this.projects = projects;
}
}
Run Code Online (Sandbox Code Playgroud)

任务类

@Entity
public class Task extends ABaseEntity{

private Map<Project, User> projectUserMap = new HashMap<>();

@ManyToMany(
        fetch = FetchType.EAGER,
        cascade = CascadeType.ALL
)
@JoinTable(
        name = "Collaborators",
        joinColumns = @JoinColumn(name = "Task_ID", referencedColumnName = "id", updatable = false, nullable = false),
        inverseJoinColumns = @JoinColumn(name = "User_ID", referencedColumnName = "id", updatable = false, nullable = false)
)
@MapKeyJoinColumn(name = "Project_Id")
public Map<Project, User> getProjectUserMap() {
    return projectUserMap;
}

public void setProjectUserMap(Map<Project, User> projectUserMap) {
    this.projectUserMap = projectUserMap;
}
}
Run Code Online (Sandbox Code Playgroud)

您的任务类别有什么问题:

@MapKeyJoinColumn(name = "User_id")
Run Code Online (Sandbox Code Playgroud)

@MapKeyJoinColumn 用于映射键的列,这里是 Project 实体。

@ElementCollection
Run Code Online (Sandbox Code Playgroud)

如果映射的值为@Embeddable,则使用

@JoinTable
Run Code Online (Sandbox Code Playgroud)

定义实体类与Map值中定义的实体之间的关系(这里是任务和用户之间的关系)。

 targetEntity = User.class
Run Code Online (Sandbox Code Playgroud)

所有 targetEntity 都是多余的,因为您使用了具有定义的泛型类型的集合。

而且,你不必像这样配置3个类。据我了解,您只需要一个包含这三个类之间关系的表。因此,只需定义一个名为 Collaboration 的实体,如下所示:

@Entity
public class Collaboration{
  @ManyToOne
  private User user;
  @ManyToOne
  private Task task;
  @ManyToOne
  private Project project;
}
Run Code Online (Sandbox Code Playgroud)

通过分离的 Collaboration 实体,您可以找到给定 User 的所有协作。

如果没有这个实体,您可以编写一个查询来查找与给定用户相关的所有任务,然后当然可以自己用 java 代码收集项目和任务。查询将类似于

 'Select t from Task t join projectUserMap m where m = :user '
Run Code Online (Sandbox Code Playgroud)