【问题标题】:Hibernate - WrongClassException休眠 - WrongClassException
【发布时间】:2021-10-21 22:58:24
【问题描述】:

这是我正在构建的音乐系统领域模型的一部分:

@Entity
@Table(name="library_entities", schema="myschema")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="entity_type", discriminatorType = DiscriminatorType.STRING)
public abstract class LibraryEntity {

    public LibraryEntity() {}
    
    // ... some fields and their getters/setters ...

}

@Entity
public abstract class Artist extends LibraryEntity {
    
    public Artist() {}

    @OneToMany(mappedBy="artist")
    private Set<Album> albums = new HashSet<>();

    @OneToMany(mappedBy="artist")
    private Set<Track> tracks = new HashSet<>();

    // ... some Artist-specific fields and their getters/setters

    public Set<Album> getAlbums() {
        return this.albums;
    }

    public Set<Track> getTracks() {
        return this.tracks;
    }

}

@Entity
@DiscriminatorValue("B")
public class Band extends Artist {

    public Band() {}

    // ...        
    private Set<Singer> members = new HashSet<>();

}

@Entity
@DiscriminatorValue("S")
public class Singer extends Artist {

    public Singer() {}

    @ManyToMany(mappedBy="members")
    private Set<Band> bands;

}

@Entity
@DiscriminatorValue("A")
public class Album extends LibraryEntity {

    public Album() {}

    @ManyToOne
    @JoinColumn(name="artist_id")
    private Artist artist;

    @OneToMany(mappedBy="album")
    private Set<Track> tracks = new HashSet<>();

    public Set<Track> getTracks() {
        return this.tracks;
    }

}

@Entity
@DiscriminatorValue("T")
public class Track extends LibraryEntity {

    public Track() {}

    @ManyToOne
    @JoinColumn(name="artist_id")
    private Artist artist;

    @ManyToOne
    @JoinColumn(name="album_id")
    private Album album;

    public Artist getArtist() {
        return this.artist;
    }

    public Album getAlbum() {
        return this.album;
    }

}

生成的架构(如预期):

--------------------------------------------
| entity_type | ... | album_id | artist_id |
--------------------------------------------

一切正常,但是当我运行以下代码时:

public class AppMain {

    public static void main(String[] args) {

        final List<Artist> results =
            entityManager
            .createQuery("SELECT artist FROM Artist artist")
            .getResultList();

        try {

            for(Artist artist : results) {
                artist.getTracks(); // works fine
                artist.getAlbums(); // throws WrongClassException
            }
            
        } catch(Exception e){
            e.printStackTrack();
        }            

    }

}

通过跟踪 Hibernate 生成的 SQL 查询,很明显 Hibernate 错误地将 Track 获取为 Album,从而抛出了 WrongClassException

org.hibernate.WrongClassException: Object [id=93c348c2-fb21-4239-9e47-63ef08ae3040] 
was not of the specified subclass [com.database.Models.Album] : loaded object was of 
wrong class class com.database.Models.Track

我在这里做错了什么?请帮忙。

[更新]
我意识到通过第一次调用artist.getAlbums(),第二次调用(artist.getTracks())失败了。第一次调用 artist.getTracks(),第二次调用 (artist.getAlbums()) 失败。

[更新 2]
当我删除时问题消失了:

public class Album extends LibraryEntity {

    @ManyToOne                      // removed
    @JoinColumn(name="artist_id")   // removed
    private Artist artist;          // removed

}
public class Artist extends LibraryEntity {

    @OneToMany(mappedBy="artist")   // removed
    private Set<AlbumModel> albums = new HashSet<AlbumModel>(); //removed

}

但是,这种关系是绝对需要的,因为 Track 可以是单个轨道(因此需要对 Artist 的引用)。而Album 肯定也需要这种关系。

【问题讨论】:

  • Track 和 Album 是否也映射到带有鉴别器的单个表?我怀疑错误出在这些实体中。
  • 你能帮我解决这个问题吗? @vlad-mihalcea
  • 能分享一下'select * from library_entities'的结果集吗
  • 请发布您的albumtrack 实体
  • java.lang.IllegalArgumentException: org.hibernate.hql.internal.ast.QuerySyntaxException: LibrarytEntity is not mapped [SELECT entity FROM LibrarytEntity entity]@null

标签: java hibernate jpa orm hibernate-onetomany


【解决方案1】:

当您在AlbumTrack 上使用@DiscriminatorOptions(force = true) 来强制为关联连接添加类型鉴别器约束时,这应该可以工作。

【讨论】:

【解决方案2】:

我似乎找到了解决办法。
根据this,两个类(在本例中为AlbumTrack)不应该使用相同的连接列(尽管我认为应该有这样的能力)。 所以通过创建album_artist_idtrack_artist_id,问题就解决了。

编辑:
我找到了更好的解决方案。 我添加了另一个名为 Artwork 的抽象类,其中包含对类 Artist 的引用。
AlbumTrack 都派生自 Artwork
Artwork 也标有 @MappedSuperclass 注释。
并且AlbumTrack 已更改为:

@Entity
@DiscriminatorValue("A")
@AssociationOverride(name="artist", 
    joinColumns=@JoinColumn(name="album_artist_id"))
public class Album extends Artwork {
    ...
}

@Entity
@DiscriminatorValue("T")
@AssociationOverride(name="artist", 
    joinColumns=@JoinColumn(name="track_artist_id"))
public class Track extends Artwork {
    ...
}

最后我们仍然有两个外键,但从 OOP 的角度来看,它是固定的。
让我知道你的意见。

【讨论】:

    猜你喜欢
    • 2011-12-16
    • 2010-11-19
    • 2015-02-08
    • 2019-04-18
    • 2017-02-06
    • 2017-05-18
    • 2017-09-19
    • 2013-10-19
    • 2010-10-14
    相关资源
    最近更新 更多