3

在这个问题中,我正在使用 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
}

我有几种类型的卡片,每一种都扩展了 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> {

}

@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 {
}

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

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

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

        Hibernate.initialize(user.getCards());

        return user;

“卡片”
数据库条目
的数据库条目 “卡片实例”的数据库条目
数据库条目


org.hibernate.WrongClassException: Object [id=1] was not of the specified subclass [org.gwentonline.model.cards.UnitCard] : Discriminator: leader

提前感谢您提供如何解决此问题的任何线索。如果您需要更多信息,我很乐意更新我的问题!

4

2 回答 2

7

根据JavaDocs的第一段@ManyToOne

通常不需要明确指定目标实体,因为它通常可以从被引用的对象的类型中推断出来。

但是,在这种情况下,@ManyToOne是在类型为泛型的字段上,泛型类型信息在编译类型时被删除。因此,在反序列化时,Hibernate 并不知道该字段的确切类型。

解决方法是添加targetEntity=Card.class@ManyToOne. 由于Cardisabstract和 has@Inheritance以及@DiscriminatorColumn注解,这迫使 Hibernate 以所有可能的方式解析实际的字段类型。它使用Card表的鉴别器值来执行此操作并生成正确的类实例。此外,Java 代码中保留了类型安全性。


因此,一般来说,只要有可能在运行时无法完全了解字段类型,请使用targetEntitywith@ManyToOne@OneToMany

于 2015-07-10T14:52:13.300 回答
0

我解决了这个问题。

根本原因在于这样的设计:

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

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

在运行时有关类的泛型类型的信息在 java 中不存在。有关详细信息,请参阅此问题:Java 泛型 - 类型擦除 - 何时发生以及发生了什么

这意味着 hibernate 无法确定CardInstance类的实际类型。


解决这个问题的方法是简单地摆脱泛型类型和所有扩展(实现)类,只使用一个像这样的类:

@Table
@Entity
@Inheritance
@DiscriminatorColumn(name = "card_type", discriminatorType = DiscriminatorType.STRING)
public class CardInstance {
    Card card;
}

这是可能的(顺便说一下更好的设计),因为会员card携带有关卡类型的所有信息。


如果遇到同样的问题,我希望这对人们有所帮助。

于 2015-07-07T10:33:47.873 回答