【问题标题】:I'm trying to get an entity field through a copied entity我正在尝试通过复制的实体获取实体字段
【发布时间】:2019-08-28 16:18:11
【问题描述】:

我有 2 个实体:歌手和专辑。歌手有几张专辑。我复制了歌手的精华,可以得到他的ID和名字,但是我无法得到他的专辑列表。 我有这个例外

线程“主”org.hibernate.LazyInitializationException 中的异常:无法延迟初始化角色集合: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 && 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();
}

}

【问题讨论】:

    标签: java hibernate


    【解决方案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 将附加到 Hibernate 会话。例如,您可以在方法上使用 Spring @Transactional 注释。

    我没有看到你的 DAO 代码,但 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 && session.isOpen()){
                session.close();
            }
        }
        return singer;
    }
    

    【讨论】:

    • 感谢您的回答,但我不太明白您的意思。你能写出main方法的代码吗?
    • 我只需要在控制台中显示所有艺术家专辑的名称。
    • 我得到了这个例外:“实体映射中的重复列:Entity.AlbumEntity 列:singer_id(应使用 insert="false" update="false")"
    • 你不能有私有的intsinger_id;和私人 SingerEntity 歌手;在一个实体中。你应该删除intsinger_id,异常就会消失。
    • 我不能删除singer_id,因为这是实体的主键
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-17
    • 2014-08-11
    • 1970-01-01
    • 2012-06-20
    相关资源
    最近更新 更多