Java Hibernate失败,将完全限定类名前置到多个关联的属性名

Java Hibernate失败,将完全限定类名前置到多个关联的属性名,java,hibernate,Java,Hibernate,我试图使用manytomy关联将两个对象映射到彼此,但由于某种原因,当我使用mappedBy属性时,hibernate似乎对我映射的确切内容感到困惑。关于我在这里的映射,唯一奇怪的是关联不是在其中一个条目的主键字段上完成的(尽管该字段是唯一的) 各表如下: Sequence ( id NUMBER, reference VARCHAR, ) Project ( id NUMBER ) Sequence_Project ( proj_id number references P

我试图使用
manytomy
关联将两个对象映射到彼此,但由于某种原因,当我使用mappedBy属性时,hibernate似乎对我映射的确切内容感到困惑。关于我在这里的映射,唯一奇怪的是关联不是在其中一个条目的主键字段上完成的(尽管该字段是唯一的)

各表如下:

Sequence (
  id NUMBER,
  reference VARCHAR,
)

Project (
  id NUMBER
)

Sequence_Project (
  proj_id number references Project(id),
  reference varchar references Sequence(reference)
)
对象看起来像(注释在getter上,将它们放在字段上以进行压缩):

类序列{
@身份证
私有int-id;
私有字符串引用;
@许多(mappedBy=“序列”)
私人清单项目;
}
而拥有方:

class Project {
    @Id
    private int id;

    @ManyToMany
    @JoinTable(name="sequence_project",
               joinColumns=@JoinColumn(name="id"),
               inverseJoinColumns=@JoinColumn(name="reference", 
                                     referencedColumnName="reference"))
    private List<Sequence> sequences;
}
类项目{
@身份证
私有int-id;
@许多
@JoinTable(name=“sequence\u project”,
joinColumns=@JoinColumn(name=“id”),
inverseJoinColumns=@JoinColumn(name=“reference”,
referencedColumnName=“reference”))
私有列表序列;
}
此操作失败,出现映射异常:

在实体[test.local.entities.Project]上找不到属性ref[\u test\u local\u entities\u Project\u sequences]

它似乎奇怪地在完全限定类名前面加上下划线。我怎样才能避免这种情况发生

编辑: 我又玩了一会儿。更改mappedBy属性的名称会引发不同的异常,即:

org.hibernate.AnnotationException:mappedBy引用未知的目标实体属性:test.local.entities.Project.sequences


因此注释处理正确,但是属性引用没有正确地添加到Hibernate的内部配置中。

我最终或多或少地找到了答案。我认为这基本上是一个休眠错误

编辑:我试图通过更改关联的拥有方来修复它:

class Sequence {
  @Id
  private int id;

  private String reference;

  @ManyToMany
  @JoinTable(name="sequence_project",
           inverseJoinColumns=@JoinColumn(name="id"),
           joinColumns=@JoinColumn(name="reference", 
                        referencedColumnName="reference"))
  private List<Project> projects;
}

class Project {
  @Id
  private int id;

  @ManyToMany(mappedBy="projects")
  private List<Sequence> sequences;
}
类序列{
@身份证
私有int-id;
私有字符串引用;
@许多
@JoinTable(name=“sequence\u project”,
inverseJoinColumns=@JoinColumn(name=“id”),
joinColumns=@JoinColumn(name=“reference”,
referencedColumnName=“reference”))
私人清单项目;
}
班级项目{
@身份证
私有int-id;
@许多(mappedBy=“项目”)
私有列表序列;
}

这起到了作用,但在其他地方引发了问题(见评论)。所以我放弃了,将关联建模为一个实体,在序列和项目中有多对一的关联。我认为这至少是一个文档/故障处理错误(异常不是很相关,故障模式是错误的),并将尝试将其报告给Hibernate开发人员。

IMHO使用JPA/Hibernate注释无法实现您的目标。不幸的是,这里的APIDoc有点不清楚,但我发现的所有示例在映射联接表时都使用主键


我们在一个项目中遇到了与您相同的问题,我们也无法更改遗留数据库模式。唯一可行的选择是转储Hibernate并使用MyBatis()在这里,您可以完全灵活地使用本机SQL来表示更复杂的联接条件。

我已经多次遇到这个问题,我找到的唯一解决方法是在关系的另一侧使用交换列两次配置
@JoinTable

class Sequence {

    @Id
    private int id;

    private String reference;

    @ManyToMany
    @JoinTable(
        name = "sequence_project",
        joinColumns = @JoinColumn(name="reference", referencedColumnName="reference"),
        inverseJoinColumns = @JoinColumn(name="id")
    )
    private List<Project> projects;

}

class Project {

    @Id
    private int id;

    @ManyToMany
    @JoinTable(
        name = "sequence_project",
        joinColumns = @JoinColumn(name="id"),
        inverseJoinColumns = @JoinColumn(name="reference", referencedColumnName="reference")
    )
    private List<Sequence> sequences;

}
类序列{
@身份证
私有int-id;
私有字符串引用;
@许多
@可接合(
name=“sequence\u项目”,
joinColumns=@JoinColumn(name=“reference”,referencedColumnName=“reference”),
inverseJoinColumns=@JoinColumn(name=“id”)
)
私人清单项目;
}
班级项目{
@身份证
私有int-id;
@许多
@可接合(
name=“sequence\u项目”,
joinColumns=@JoinColumn(name=“id”),
inverseJoinColumns=@JoinColumn(name=“reference”,referencedColumnName=“reference”)
)
私有列表序列;
}

我还没有尝试使用与主键不同的列。

我已经完成了与您的问题相同的场景。正如所料,我得到了同样的例外。作为补充任务,我使用非主键作为连接列(如reference),完成了相同的场景,但是使用了一对多对一。我现在明白了

SecondaryTable JoinColumn不能引用非主键

那么,它会是一只虫子吗???嗯,是的(而且你的变通方法很好(+1))。如果要将非主键用作主键,必须确保它是唯一的。也许这解释了为什么Hibernate不允许使用非主键作为主键(不知情的用户可能会出现意外行为)

如果要使用相同的映射,可以使用封装将@manytomy关系拆分为@OneToMany manytomone,您无需担心加入的类

项目

@Entity
public class Project implements Serializable {

    @Id
    @GeneratedValue
    private Integer id;

    @OneToMany(mappedBy="project")
    private List<ProjectSequence> projectSequenceList = new ArrayList<ProjectSequence>();

    @Transient
    private List<Sequence> sequenceList = null;

    // getters and setters

    public void addSequence(Sequence sequence) {
        projectSequenceList.add(new ProjectSequence(new ProjectSequence.ProjectSequenceId(id, sequence.getReference())));
    }

    public List<Sequence> getSequenceList() {
        if(sequenceList != null)
            return sequenceList;

        sequenceList = new ArrayList<Sequence>();
        for (ProjectSequence projectSequence : projectSequenceList)
            sequenceList.add(projectSequence.getSequence());

        return sequenceList;
    }

}

可能看起来像SQ,但项目上有公共getSequences和公共setSequences吗?@Aff我会仔细检查,我认为目前它是公共的/受保护的。以防万一,如果将
sequences
属性重命名为其他属性(例如
foo
),会发生什么情况?@PascalThivent当我在mappedBy中更改名称时,会发生同样的事情,抛出一个注释异常。这不是我的意思,我指的是不动产名称
private List foos
(当然还有
mappedBy=“foos”
)。进一步的检查表明这不起作用,因为现在hibernate正试图将关联表中的字符串列与实体的id列连接起来。不知怎么的,这么简单似乎是不可能做到的。我想你可能是对的。事实上,我可以更改模式的一部分,因此理论上我可以重做联接表以使用ID,但这将需要更多的工作,因此我需要
@Entity
public class Project implements Serializable {

    @Id
    @GeneratedValue
    private Integer id;

    @OneToMany(mappedBy="project")
    private List<ProjectSequence> projectSequenceList = new ArrayList<ProjectSequence>();

    @Transient
    private List<Sequence> sequenceList = null;

    // getters and setters

    public void addSequence(Sequence sequence) {
        projectSequenceList.add(new ProjectSequence(new ProjectSequence.ProjectSequenceId(id, sequence.getReference())));
    }

    public List<Sequence> getSequenceList() {
        if(sequenceList != null)
            return sequenceList;

        sequenceList = new ArrayList<Sequence>();
        for (ProjectSequence projectSequence : projectSequenceList)
            sequenceList.add(projectSequence.getSequence());

        return sequenceList;
    }

}
@Entity
public class Sequence implements Serializable {

    @Id
    private Integer id;
    private String reference;

    @OneToMany(mappedBy="sequence")
    private List<ProjectSequence> projectSequenceList = new ArrayList<ProjectSequence>();

    @Transient
    private List<Project> projectList = null;

    // getters and setters

    public void addProject(Project project) {
        projectSequenceList.add(new ProjectSequence(new ProjectSequence.ProjectSequenceId(project.getId(), reference)));
    }

    public List<Project> getProjectList() {
        if(projectList != null)
            return projectList;

        projectList = new ArrayList<Project>();
        for (ProjectSequence projectSequence : projectSequenceList)
            projectList.add(projectSequence.getProject());

        return projectList;
    }

}
@Entity
public class ProjectSequence {

    @EmbeddedId
    private ProjectSequenceId projectSequenceId;

    @ManyToOne
    @JoinColumn(name="ID", insertable=false, updatable=false)
    private Project project;

    @ManyToOne
    @JoinColumn(name="REFERENCE", referencedColumnName="REFERENCE", insertable=false, updatable=false)
    private Sequence sequence;

    public ProjectSequence() {}
    public ProjectSequence(ProjectSequenceId projectSequenceId) {
        this.projectSequenceId = projectSequenceId;
    }

    // getters and setters

    @Embeddable
    public static class ProjectSequenceId implements Serializable {

        @Column(name="ID", updatable=false)
        private Integer projectId;

        @Column(name="REFERENCE", updatable=false)
        private String reference;

        public ProjectSequenceId() {}
        public ProjectSequenceId(Integer projectId, String reference) {
            this.projectId = projectId;
            this.reference = reference;
        }

        @Override
        public boolean equals(Object o) {
            if (!(o instanceof ProjectSequenceId))
                return false;

            final ProjectSequenceId other = (ProjectSequenceId) o;
            return new EqualsBuilder().append(getProjectId(), other.getProjectId())
                                      .append(getReference(), other.getReference())
                                      .isEquals();
        }

        @Override
        public int hashCode() {
            return new HashCodeBuilder().append(getProjectId())
                                        .append(getReference())
                                        .hashCode();
        }

    }

}