关于通过Hibernate保存实体的org.hibernate.WrongClassException

Jul*_*ger 2 java spring hibernate jpa spring-orm

在这个问题中,我正在使用Hibernate 4.3.4.Final和Spring ORM 4.1.2.RELEASE.

我有一个User类,它包含一组这样的CardInstances:

@Entity
@Table
public class User implements UserDetails {

    protected List<CardInstance> cards;

    @ManyToMany
    public List<CardInstance> getCards() {
        return cards;
    }

    // setter and other members/methods omitted 
}

@Table
@Entity
@Inheritance
@DiscriminatorColumn(name = "card_type", discriminatorType = DiscriminatorType.STRING)
public abstract class CardInstance<T extends Card> {

    private T card;

    @ManyToOne
    public T getCard() {
        return card;
    }
}

@Table
@Entity
@Inheritance
@DiscriminatorOptions(force = true)
@DiscriminatorColumn(name = "card_type", discriminatorType = DiscriminatorType.STRING)
public abstract class Card {
    // nothing interesting here
}
Run Code Online (Sandbox Code Playgroud)

我有几种类型的卡,每种卡都扩展了Card基类和CardInstance基类,分别如下:

@Entity
@DiscriminatorValue("unit")
public class UnitCardInstance extends CardInstance<UnitCard> {
    // all types of CardInstances extend only the CardInstance<T> class
}

@Entity
@DiscriminatorValue("leader")
public class LeaderCardInstance extends CardInstance<LeaderCard> {

}
Run Code Online (Sandbox Code Playgroud)
@Entity
@DiscriminatorValue("unit")
public class UnitCard extends Card {
}

@Entity
@DiscriminatorValue("leader")
public class LeaderCard extends AbilityCard {
}

@Entity
@DiscriminatorValue("hero")
public class HeroCard extends UnitCard {
    // card classes (you could call them the definitions of cards) can
    // extend other types of cards, not only the base class
}

@Entity
@DiscriminatorValue("ability")
public class AbilityCard extends Card {
}
Run Code Online (Sandbox Code Playgroud)

如果我将一个UnitCardInstance或一个HeroCardInstance添加到卡集合并保存实体,一切正常.但是如果我将一个AbilityCardInstance添加到集合中并使用org.hibernate.WrongClassException保存实体失败.我在帖子的底部添加了确切的异常+消息.

我读了一些问题,在处理基类的集合时,延迟加载似乎是一个问题,所以这里是我在添加卡并保存之前加载User实体的方法:

User user = this.entityManager.createQuery("FROM User u " +
                "WHERE u.id = ?1", User.class)
                .setParameter(1, id)
                .getSingleResult();

        Hibernate.initialize(user.getCards());

        return user;
Run Code Online (Sandbox Code Playgroud)

"卡"的数据库条目

"cardinstances"的数据库条目


org.hibernate.WrongClassException: Object [id=1] was not of the specified subclass [org.gwentonline.model.cards.UnitCard] : Discriminator: leader
Run Code Online (Sandbox Code Playgroud)

提前感谢任何线索如何解决这个问题.如果您需要其他信息,我很乐意更新我的问题!

man*_*ish 6

根据JavaDocs的第一段@ManyToOne:

它是通常不需要显式指定目标实体,因为它通常可以从对象的被引用类型来推断.

但是,在您的情况下,@ManyToOne是在类型为通用的字段上,并且通用类型信息在编译类型中被擦除.因此,在反序列化时,Hibernate不知道该字段的确切类型.

修复是添加targetEntity=Card.class@ManyToOne.由于Cardabstract和拥有@Inheritance@DiscriminatorColumn注释,这迫使Hibernate通过所有可能的方式解析实际的字段类型.它使用Card表的鉴别器值来执行此操作并生成正确的类实例.另外,您在Java代码中保留了类型安全性.


因此,在一般情况下,只要有一个字段的类型完全在运行时不知道的机会,使用targetEntity@ManyToOne@OneToMany.