#java #hibernate
#java #спящий режим
Вопрос:
У меня есть 2 объекта: исполнитель и альбом. У певца есть несколько альбомов. Я скопировал сущность певца и могу получить его идентификатор и имя, но я не могу получить список его альбомов. У меня есть это исключение
Исключение в потоке «main» org.hibernate.Исключение LazyInitializationException: не удалось лениво инициализировать коллекцию role: Entity.SingerEntity.albums, не удалось инициализировать прокси-сервер — нет сеанса
@Entity
@Table(name = ""singer"")
public class SingerEntity {
@Id
private int singer_id;
private String name;
@OneToMany(mappedBy = "singer_id", cascade = CascadeType.ALL, orphanRemoval = true)
private List<AlbumEntity> albums;
public List<AlbumEntity> getAlbums() {
return albums;
}
public void setAlbums(List<AlbumEntity> albums) {
this.albums = albums;
}
@Entity
@Table(name = "album")
public class AlbumEntity {
@Id
private int album_id;
private String album_title;
private String genre;
private int singer_id;
основной метод:
public static void main(String[] args) {
SingerDAO sDAO = new SingerDAO();
AlbumDAO aDAO = new AlbumDAO();
SingerEntity s1 = new SingerEntity(1, "Singer");
sDAO.insert(s1);
AlbumEntity a1 = new AlbumEntity(1, "a1", "g1", s1);
AlbumEntity a2 = new AlbumEntity(2, "a2", "g1", s1);
AlbumEntity a3 = new AlbumEntity(3, "a3", "g2", s1);
AlbumEntity a4 = new AlbumEntity(4, "a4", "g2", s1);
aDAO.insert(a1);
aDAO.insert(a2);
aDAO.insert(a3);
aDAO.insert(a4);
s1 = sDAO.findById(1);
System.out.println(s1.getId() " , " s1.getName());
List<AlbumEntity> albums = s1.getAlbums();
System.out.println(albums.get(0).getAlbum_title());
}
класс SingerDAO:
public class SingerDAO {
public SingerEntity findById(int id) {
Session session = null;
SingerEntity singer = null;
try {
session = HibernateUtil.getSessionFactory().openSession();
singer = (SingerEntity) session.get(SingerEntity.class, id);
Hibernate.initialize(singer);
} catch (Exception e){
e.printStackTrace();
} finally {
if (session != null amp;amp; session.isOpen()){
session.close();
}
}
return singer;
}
public void select(){
Session session = HibernateUtil.getSessionFactory().openSession();
session.beginTransaction();
Query query= session.createQuery("from SingerEntity");
List<SingerEntity> list = query.list();
for (SingerEntity s:list) {
System.out.println(s.getName());
}
session.getTransaction().commit();
session.close();
}
public void insert(SingerEntity singerEntity){
Session session = HibernateUtil.getSessionFactory().openSession();
session.beginTransaction();
session.save(singerEntity);
session.getTransaction().commit();
session.close();
}
public void update(SingerEntity sE){
Session session = HibernateUtil.getSessionFactory().openSession();
session.beginTransaction();
session.update(sE);
session.getTransaction().commit();
session.close();
}
public void delete(SingerEntity sE){
Session session = HibernateUtil.getSessionFactory().openSession();
session.beginTransaction();
session.delete(sE);
session.getTransaction().commit();
session.close();
}
}
Ответ №1:
Прежде всего, правильно сопоставьте двунаправленное отношение OneToMany. У вас должно быть
@Entity
@Table(name = "singer")
public class SingerEntity {
...
@OneToMany(mappedBy = "singer", cascade = CascadeType.ALL, orphanRemoval = true)
private List<AlbumEntity> albums;
...
}
@Entity
@Table(name = "album")
public class AlbumEntity {
...
@ManyToOne
@JoinColumn(name = "singer_id)
private SingerEntity singer;
....
}
Если вы хотите добавить альбом в объект, лучше использовать пользовательский метод для объекта Singer, чтобы ссылки были правильными, например:
public void addAlbum(AlbumEntity a) {
albums.add(a);
a.setSinger(this);
}
После этого вы можете сохранять альбомы, просто сохраняя исполнителя, поскольку у вас есть опция каскада.
Затем, поскольку коллекция отношений OneToMany по умолчанию является ленивой, вы должны загрузить ее в той же транзакции, где вы получаете SingerEntity. Таким образом, SingerEntity будет присоединен к сеансу гибернации. Вы можете использовать аннотацию Spring @ Transactional в своем методе, например.
Я не вижу ваш код DAOs, но main может посмотреть:
SingerDAO sDAO = new SingerDAO();
AlbumDAO aDAO = new AlbumDAO();
SingerEntity s1 = new SingerEntity(1,"Singer");
s1.addAlbum(new AlbumEntity(1,"a1","g1",1));
s1.addAlbum(new AlbumEntity(2,"a2","g2",1));
s1.addAlbum(new AlbumEntity(3,"a3","g3",1));
s1.addAlbum(new AlbumEntity(4,"a4","g4",1));
sDAO.insert(s1);
Измените findById, чтобы использовать одну транзакцию для отложенной загрузки:
public SingerEntity findById(int id) {
Session session = null;
SingerEntity singer = null;
try {
session = HibernateUtil.getSessionFactory().openSession();
//start transaction
singer = (SingerEntity) session.get(SingerEntity.class, id);
Hibernate.initialize(singer);
//end transaction
} catch (Exception e){
e.printStackTrace();
} finally {
if (session != null amp;amp; session.isOpen()){
session.close();
}
}
return singer;
}
Комментарии:
1. Спасибо за ответ, но я не совсем понимаю, что вы имеете в виду. Не могли бы вы написать код для метода main?
2. Все, что мне нужно, это отобразить названия всех альбомов исполнителя в консоли.
3. Я получаю это исключение: «Повторяющийся столбец в сопоставлении для объекта: Сущность. Столбец AlbumEntity: singer_id (должен быть сопоставлен с insert =»false», update =»false»)»
4. У вас не может быть private int_id_позывателя; и private SingerEntity singer; в одном объекте. Вы должны удалить int singer_id, исключение исчезнет.
5. Я не могу удалить singer_id, потому что это первичный ключ сущности