Сбой Hibernate, добавление полного имени класса к имени свойства в ассоциации ManyToMany - PullRequest
7 голосов
/ 03 сентября 2010

Я пытаюсь сопоставить два объекта друг другу, используя ассоциацию ManyToMany, но по какой-то причине, когда я использую свойство mappedBy, hibernate, похоже, запутывается в том, что именно я отображаю. Единственное, что странно в моем отображении, это то, что связь не выполняется в поле первичного ключа в одной из записей (хотя это поле уникально).

Таблицы:

Sequence (
  id NUMBER,
  reference VARCHAR,
)

Project (
  id NUMBER
)

Sequence_Project (
  proj_id number references Project(id),
  reference varchar references Sequence(reference)
)

Объекты выглядят так (аннотации находятся на геттере, поместите их в поля, чтобы немного сжать):

class Sequence {
   @Id
   private int id;

   private String reference;

   @ManyToMany(mappedBy="sequences")
   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;
}

Сбой MappingException:

property-ref [_test_local_entities_Project_sequence] не найден в объекте [test.local.entities.Project]

Кажется странным добавление полностью определенного имени класса, разделенного подчеркиванием. Как я могу избежать этого?

EDIT: Я играл с этим немного больше. Изменение имени свойства mappedBy вызывает другое исключение, а именно:

org.hibernate.AnnotationException: mappedBy ссылается на неизвестное целевое свойство объекта: test.local.entities.Project.sequence

Таким образом, аннотация обрабатывается правильно, но каким-то образом ссылка на свойство неправильно добавлена ​​во внутреннюю конфигурацию Hibernate.

Ответы [ 4 ]

3 голосов
/ 10 сентября 2010

Я сделал тот же сценарий, предложенный вашим вопросом.И, как и ожидалось, я получаю то же исключение.Так же, как дополнительная задача, я выполнил тот же сценарий , но с одним ко многим, многие к одному , используя не первичный ключ в качестве объединенного столбца , например, ссылку.Теперь я получаю

SecondaryTable JoinColumn не может ссылаться на не первичный ключ

Ну, это может быть ошибкой ???Ну, да (и ваш обходной путь отлично работает (+1)).Если вы хотите использовать не первичный ключ в качестве первичного ключа , вы должны убедиться, что он уникален .Возможно, это объясняет, почему Hibernate не позволяет использовать не первичный ключ в качестве первичного ключа (пользователи, не знающие о себе, могут получить непредвиденное поведение).

Если вы хотите использовать одно и то же сопоставление, вы можете разделить ваши отношения @ManyToMany на @ OneToMany-ManyToOne Используя инкапсуляцию , вам не нужно беспокоиться о вашем присоединенном классе

Проект

@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;
    }

}

ProjectSequence

@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();
        }

    }

}
2 голосов
/ 06 сентября 2010

Я наконец понял, более или менее.Я думаю, что это в основном ошибка в спящем режиме.

редактировать: я пытался исправить это, изменив сторону связи:

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;
}

Это сработало, но в других местах возникли проблемы (см. Комментарий).Таким образом, я отказался и смоделировал ассоциацию как сущность с множественными связями в Sequence и Project.Я думаю, что это как минимум ошибка документации / обработки ошибок (исключение не очень уместно, а режим сбоя просто неправильный), и я попытаюсь сообщить об этом разработчикам Hibernate.

0 голосов
/ 08 сентября 2010

Я сталкиваюсь с этой проблемой уже дюжину раз, и единственный найденный мной обходной путь - выполнить настройку @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;

}

Я еще не пробовал использовать столбец, отличный от первичного ключа.

0 голосов
/ 08 сентября 2010

ИМХО, что вы пытаетесь достичь, невозможно с аннотациями JPA / Hibernate.К сожалению, APIDoc JoinTable здесь немного неясен, но все примеры, которые я обнаружил, используют первичные ключи при отображении таблиц соединений.

У нас была такая же проблема, как и у вас, в проекте, где мы также не могли изменить устаревшую схему базы данных.Единственным жизнеспособным вариантом был дамп Hibernate и использование MyBatis (http://www.mybatis.org), где вы имеете полную гибкость нативного SQL для выражения более сложных условий соединения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...