Как отладить "Найдено два представления одной коллекции"? - PullRequest
14 голосов
/ 14 декабря 2011

Я нашел несколько вопросов о этом, но нет ни одного с полным объяснением проблемы и как ее отладить - все ответы анекдотичны.

Проблема в том, что в тесте Play 1.2.4 JPA я получаю это исключение, когда я save() модель:

org.hibernate.HibernateException: Foundдва представления одной коллекции: models.Position.projects

Я хотел бы знать:

  1. Есть ли документация по этой проблеме в целом, не связанная с Play?Проблема в спящем режиме, но многие результаты Google по этому вопросу находятся в приложениях Play.
  2. Каковы основные рекомендации по устранению этой проблемы?
  3. Это вызвано Play?Или я что-то не так делаю?
  4. Как решить в моем конкретном случае?

Вот воспроизведение проблемы на github .У меня есть четыре объекта:

@Entity
public class Person extends Model {
    public String name;

    @OneToMany(cascade = CascadeType.ALL)
    public List<Position> positions;
}


@Entity
public class Position extends Model {
    public Position(){}
    public Position(Company companies) {
        this.companies = companies;
        this.projects = new ArrayList<Project>();
    }

    @OneToOne
    public Company companies;

    @ManyToOne
    public Person person;

    @OneToMany
    public List<Project> projects;
}

@Entity
public class Company extends Model {
    public String name;
}

@Entity
public class Project extends Model {
    public Project(){}
    public Project(String field, String status){
        this.theField = field;
        this.status = status;
    }

    @ManyToOne
    public Position position;

    public String theField;
    public String status;
}

И мой код персистентности:

Company facebook = new Company();
facebook.name = "Facebook";
facebook.save();
Company twitter = new Company();
twitter.name = "Twitter";
twitter.save();

Person joe = new Person();
joe.name = "Joe";
joe.save();

joe.positions = new ArrayList<Position>();

Position joeAtFacebook = new Position(facebook);
joeAtFacebook.projects.add(new Project("Stream", "Architect"));
joeAtFacebook.projects.add(new Project("Messages", "Lead QA"));
joe.positions.add(joeAtFacebook);

Position joeAtTwitter = new Position(twitter);
joeAtTwitter.projects.add(new Project("Steal stuff from Facebook", "CEO"));
joe.positions.add(joeAtTwitter);
joe.save();

Кстати, я пытался добавить модуль Play ассоциаций , как предложил один человек,и это, похоже, не помогает.

Я вижу, что действительно, создаваемые таблицы в некотором смысле дубликаты:

У меня есть и таблица person_position, и position table,где оба содержат одинаковые поля: person_position содержит Person_id и positions_id, а таблица position содержит id (значение идентификатора позиции), person_id и companies_id.Поэтому я понимаю, что некое непреднамеренное резервирование создается моим определением модели, но я не совсем понимаю, как его решить.

Я думал, что это может быть связано с двунаправленным отображением, но вот ветвь , где модель однонаправленная (я удалил некоторые обратные ссылки) - и проблема все еще возникает.

Ответы [ 3 ]

9 голосов
/ 15 декабря 2011

Насколько я могу судить, ошибка вызвана любой комбинацией:

  • Отсутствует / отсутствует mappedBy параметр в @OneToMany аннотациях. Этот параметр должен получить имя поля в целевой модели, которое ссылается на эту модель.
  • Old hibernate - Play 1.2.4 поставляется с hibernate 3.6.1 ... обновление до 3.6.8, похоже, решает еще одну такую ​​проблему (просто добавьте следующее в dependencies.yml и играйте deps)

- org.hibernate -> hibernate-core 3.6.8.Final:

force: true

Для меня вышеуказанные шаги решили проблему .

На самом деле это ошибка в спящем режиме, потому что она генерируется при сохранении объектов, хотя на самом деле она подразумевает проблему «времени разработки», которая должна быть обнаружена при создании схемы.

Шаги, которые я использовал для отладки:

  • Написал тест, который воспроизвел проблему
  • Добавлен модуль ассоциаций - я не уверен, что он решил часть проблемы или сделал ее хуже.
  • Отладка с помощью кода гибернации и понимание того, что это, вероятно, указывает на проблему гибернации, а не на ошибку пользователя / конфигурации.
  • Заметил, что hibernate имеет довольно много версий исправлений после 3.6.1, и решил попытать счастья и обновить.
  • Также важно, чтобы очистка папки tmp не помешала - там воспроизводятся кэши скомпилированных jar-файлов, и после значительных изменений, таких как обновление версии hibernate, возможно, стоит почистить ее.
7 голосов
/ 15 декабря 2011

Попробуйте

        @OneToMany(mappedBy="position")
        public List<Project> projects;
1 голос
/ 15 декабря 2011

Сначала я думаю, что вы пропустили одну строку перед последней:

joe.positions.add(joeAtTwitter);

Во-вторых: Я думаю, что вы не должны делать

joe.positions = new ArrayList<Position>();

вместо этого измените Person на:

@Entity
public class Person extends Model {
    public String name;

    @OneToMany(cascade = CascadeType.ALL)
    public List<Position> positions = new ArrayList<Position>();
}

Это решит вашу проблему, а также рекомендуется использовать пустую коллекцию вместо значения null (см. Эффективная Java) в целом и специально для работы с управляемыми объектами Hibernate. Прочтите первый абзац здесь , чтобы объяснить, почему лучше инициализировать с пустыми коллекциями.

Теперь я думаю, что произошло: когда вы вызываете joe.save(), вы управляете объектом (с помощью Hibernate), а затем перезаписываете свойство новой коллекцией, я не могу понять, почему возникла ошибка, о которой вы model.Position.projects, но я думаю, что это так.

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