在Hibernate中实现三元关系



我有四个表。

    用户
  1. 项目
  2. UserProjectRole

我的场景或关系是,在一个项目中,一个用户有多个角色。我对上面hibernate实体中的映射关系感到困惑。我需要帮助。

使用Hibernate实现所谓的三元关系有很多方法,可以利用"简单"映射或使用中间实体/表实现关联。您的用例决定哪一个是正确的。这取决于数据的存储方式以及读取数据的频率。报告也是一个重要的用例。

如果你想允许许多用户-项目-角色组合,映射(例如在用户实体上)是不合适的,因为你的键可能是项目或角色,一个键只能出现一次。然而,在您的系统中,每个关系项都应该是唯一的,所以在这种情况下,我倾向于使用至少具有一些唯一约束的中间表。

"快速和肮脏"的方法将是一个实体,如:

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
@Entity
@Table(uniqueConstraints = @UniqueConstraint(columnNames={"user_id", "project_id", "role_id"}))
public class UserProjectRoleSimple {
    @Id
    @GeneratedValue
    private Long id;
    @ManyToOne
    private User user;
    @ManyToOne
    private Project project;
    @ManyToOne
    private Role role;
    // you also need constructors, getters, equals, hashcode and stuff
}

另一种(更好的)方法是使用关系对象标识符作为组合键。这有点冗长,但您不需要额外的代理键,因此您的连接表更干净。

import java.io.Serializable;
import javax.persistence.Embeddable;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.validation.constraints.NotNull;
import org.hibernate.annotations.Immutable;
@Entity
@Immutable
public class UserProjectRole {
    protected UserProjectRole() {
    }
    public UserProjectRole(final User user, final Project project, final Role role) {
        this.userProjectRoleId = new UserProjectRoleId(user, project, role);
        this.user = user;
        this.project = project;
        this.role = role;
    }
    @EmbeddedId
    protected UserProjectRoleId userProjectRoleId;
    @ManyToOne
    @JoinColumn(name = "userId", insertable = false, updatable = false)
    private User user;
    @ManyToOne
    @JoinColumn(name = "projectId", insertable = false, updatable = false)
    private Project project;
    @ManyToOne
    @JoinColumn(name = "roleId", insertable = false, updatable = false)
    private Role role;
    public User getUser() {
        return user;
    }
    public Project getProject() {
        return project;
    }
    public Role getRole() {
        return role;
    }
    @Embeddable
    static class UserProjectRoleId implements Serializable {
        private static final long serialVersionUID = 7994974851694559677L;
        @NotNull
        private Long userId;
        @NotNull
        private Long projectId;
        @NotNull
        private Long roleId;
        protected UserProjectRoleId() {
        }
        protected UserProjectRoleId(final User user, final Project project, final Role role) {
            this.userId = user.getId();
            this.projectId = project.getId();
            this.roleId = role.getId();
        }
        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + ((projectId == null) ? 0 : projectId.hashCode());
            result = prime * result + ((roleId == null) ? 0 : roleId.hashCode());
            result = prime * result + ((userId == null) ? 0 : userId.hashCode());
            return result;
        }
        @Override
        public boolean equals(Object obj) {
            if (this == obj)
                return true;
            if (obj == null)
                return false;
            if (getClass() != obj.getClass())
                return false;
            UserProjectRoleId other = (UserProjectRoleId) obj;
            if (projectId == null) {
                if (other.projectId != null)
                    return false;
            } else if (!projectId.equals(other.projectId))
                return false;
            if (roleId == null) {
                if (other.roleId != null)
                    return false;
            } else if (!roleId.equals(other.roleId))
                return false;
            if (userId == null) {
                if (other.userId != null)
                    return false;
            } else if (!userId.equals(other.userId))
                return false;
            return true;
        } 
    }
}

这个映射也很简单,唯一不寻常的部分是@JoinColumn(name = "...Id", insertable = false, updatable = false)的加法。这样,您就可以使用映射实体(用于导航目的),而无需存储两次。

最新更新