在我的项目中,我需要2个具有双向多对多关系的实体。但是,联接表必须与其他表具有自己的额外关系,因此我为联接表创建了一个新实体。

它看起来应该像这样:

项目-检查员分配-用户

在将检查分配分配添加到项目中并使其持久化时,该分配也应持久化,并且用户也应添加该分配。

为此,我在服务中有一个方法:

projectService.assignInspectorToProject(inspector, project);


但是,当我两次运行此方法时,将在表中创建两条记录。因为所有集合都是集合,所以不应发生这种情况。

有人可以指出我做错了什么吗?

所有相关方法/类:

项目服务

public void assignInspectorToProject(User user, Project project) {

    if (!user.hasRole("inspector")) {
        throw new RuntimeException("This user is no inspector");
    }

    project.addInspector(user);
    projectDao.save(project);
}


项目

@Entity
public class Project extends AbstractPersistentObject {

    @OneToMany(cascade = {CascadeType.ALL}, mappedBy = "project")
    private Set<InspectorAssignment> inspectorAssignments;

    public void addInspector(User user) {

        InspectorAssignment assignment = new InspectorAssignment(user, this);
        user.addInspectorAssignment(assignment);

        inspectorAssignments.add(assignment);
    }
}


检查员分配

@Entity
public class InspectorAssignment extends AbstractPersistentObject {

    @ManyToOne
    @NotNull
    private User user;

    @ManyToOne
    @NotNull
    private Project project;

    public InspectorAssignment() {
    }

    public InspectorAssignment(User user, Project project) {
        setUser(user);
        setProject(project);
    }
}


用户

@Entity
public class User extends AbstractPersistentObject implements UserDetails {

     @OneToMany(mappedBy = "user", cascade = {CascadeType.ALL})
     private Set<InspectorAssignment> inspectorAssignments;

     public void addInspectorAssignment(InspectorAssignment assignment) {
         inspectorAssignments.add(assignment);
     }
}
}


equals和hashPercode方法在AbstractPersistenObject中(我所有实体扩展的类)

 @Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    AbstractPersistentObject other = (AbstractPersistentObject) obj;
    if (id == null) {
        if (other.id != null)
            return false;
    } else if (id.equals(other.id))
        return true;
    return false;
}

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((id == null) ? 0 : id.hashCode());
    return result;
}

最佳答案

在我看来,这很合逻辑。您两次调用此方法。因此,您将创建两个不同的InspectorAssignment实例并保存它们。即使通过保存项目来保存它们,该项目也会有一组分配,其中包含两个不同的InspectorAssignment实例。 Set不会添加与第一个相等的第二个,但不是,因为您没有覆盖hashCode()equals()

我会


在分配表中的userId-projectId上创建唯一约束,以确保不会发生这种情况并引发异常
仅在尚不存在时创建一个新的InspectorAssignment
通过显式保存在数据库中创建InspectorAssignment,而不是依靠从Project到InspectorAssignment的级联
在InspectorAssignment中覆盖equals()hashCode()

09-11 17:46