Подтвердить что ты не робот

Как отлаживать "Найдено два представления одной коллекции"?

Я нашел несколько questions about это, но никто с полным изложением проблемы и как ее отлаживать - ответы все анекдотичны.

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

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

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

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

Здесь воспроизводится проблема 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();

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

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

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

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

4b9b3361

Ответ 1

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

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

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

force: true

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

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

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

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

Ответ 2

Попробуйте

        @OneToMany(mappedBy="position")
        public List<Project> projects;

Ответ 3

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

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, но я думаю, что случай.