Отношения JPA OneToMany и ManyToOne
У меня есть три класса, одно из которых - это Пользователь, и у этого пользователя есть экземпляры других классов. Вот так:
public class User{
@OneToMany(fetch=FetchType.LAZY, cascade = CascadeType.ALL)
public List<APost> aPosts;
@OneToMany(fetch=FetchType.LAZY, cascade = CascadeType.ALL)
public List<BPost> bPosts;
}
public class BPost extends Post {
@ManyToOne(fetch=FetchType.LAZY)
public User user;
}
public class APost extends Post {
@ManyToOne(fetch=FetchType.LAZY)
public User user;
}
он работает так, но генерирует таблицы emty в db. Которые должны содержать внешние ключи. Когда я попытался использовать аннотации mappedBy и JoinColumn, я потерпел неудачу. Как я могу это решить?
Дополнительная информация:
Когда я изменил с помощью
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="id")
public User user;
и
@OneToMany(fetch=FetchType.LAZY, cascade = CascadeType.ALL, mappedBy="id")
public List<APost> aPosts;
Я получаю
Произошла ошибка JPA (невозможно построить EntityManagerFactory): повторный столбец при сопоставлении для объекта: models.post.APost column: id (должен быть сопоставлен с insert = "false" update = "false" )
Заключительное редактирование: Наконец, я ошибся в аннотации ipa.:( Когда я меняю
@OneToMany(fetch=FetchType.LAZY, cascade = CascadeType.ALL, mappedBy="id")
к
@OneToMany(fetch=FetchType.LAZY, cascade = CascadeType.ALL, mappedBy="user")
и
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="user_id")
все работает нормально.:)
Ответы
Ответ 1
Как я объяснил в этой статье, и в моей книге " Высокопроизводительное сохранение Java" вы никогда не должны использовать однонаправленную аннотацию @OneToMany
потому что:
- Он генерирует неэффективные операторы SQL
- Он создает дополнительную таблицу, которая увеличивает объем памяти ваших индексов DB
Теперь, в вашем первом примере, обе стороны владеют ассоциацией, и это плохо.
Хотя @JoinColumn
позволит стороне @OneToMany
отвечать за ассоциацию, это определенно не лучший выбор. Поэтому, всегда используйте mappedBy
атрибут на @OneToMany
стороне.
public class User{
@OneToMany(fetch=FetchType.LAZY, cascade = CascadeType.ALL, mappedBy="user")
public List<APost> aPosts;
@OneToMany(fetch=FetchType.LAZY, cascade = CascadeType.ALL, mappedBy="user")
public List<BPost> bPosts;
}
public class BPost extends Post {
@ManyToOne(fetch=FetchType.LAZY)
public User user;
}
public class APost extends Post {
@ManyToOne(fetch=FetchType.LAZY)
public User user;
}
Ответ 2
Я не уверен в вашем вопросе (значение "пустой стол" и т.д., или как mappedBy
и JoinColumn
не работают).
Я думаю, вы пытались сделать двунаправленные отношения.
Во-первых, вам нужно решить, какая сторона "владеет" отношениями. Hibernate собирается настроить базу отношений с этой стороны. Например, предположим, что я делаю стороной Post
собственную связь (я упрощаю ваш пример, просто чтобы все было в порядке), сопоставление будет выглядеть следующим образом:
(Желаю синтаксиса правильно, я пишу их только по памяти. Однако идея должна быть прекрасной)
public class User{
@OneToMany(fetch=FetchType.LAZY, cascade = CascadeType.ALL, mappedBy="user")
private List<Post> posts;
}
public class Post {
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="user_id")
private User user;
}
Таким образом, таблица для Post
будет иметь столбец user_id
, который сохранит это отношение. Hibernate получает отношение user
в Post
(вместо posts
в user
. Вы заметите разницу, если у вас есть Post
user
, но отсутствует user
posts
).
Вы упомянули mappedBy
и JoinColumn
не работает. Однако я считаю, что это на самом деле правильный путь. Скажите, не работает ли этот подход для вас и дайте нам немного больше информации о проблеме. Я считаю, что проблема связана с чем-то еще.
Edit:
Немного дополнительная информация об использовании mappedBy
, поскольку это обычно путается вначале. В mappedBy
мы помещаем "имя свойства" в противоположную сторону двунаправленного отношения, а не в имя столбца таблицы.
Ответ 3
Используете ли вы правильную конфигурацию в вашем приложении application.conf?
db=mysql://user:[email protected]/database
Я тоже столкнулся с аналогичной проблемой, решаемой, предоставив права администратора на имя пользователя db, которое вы используете в своем файле conf.
Ответ 4
Поскольку вы будете автоматически сохранять APost и BPost, это означает, что APost и BPost будут владельцем отношений. Поскольку пользователь не имеет отношения, в анноте @OneToMany будет отображаться атрибут, связанный с ним.
public class User{
@OneToMany(fetch=FetchType.LAZY, cascade = CascadeType.ALL,mappedBy="user", targetEntity = APost.class)
public List<APost> aPosts;
@OneToMany(fetch=FetchType.LAZY, cascade = CascadeType.ALL,mappedBy="user", targetEntity = BPost.class)
public List<BPost> bPosts;
}
public class BPost extends Post {
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="user_id",referencedColumnName="id")
public User user;
}
public class APost extends Post {
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="user_id",referencedColumnName="id")
public User user;
}
аннотация @JoinColumn будет отвечать за добавление внешнего ключа в Apost и BPost.