当前位置: 首页 > 知识库问答 >
问题:

组织。冬眠通过Hibernate保存实体时出现错误ClassException

蒋乐意
2023-03-14

在这个问题中,我正在使用Hibernate 4.3.4。最终和SpringORM 4.1.2。释放。

我有一个User类,它包含这样的一组Card实例:

@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添加到cards集合并保存实体,则一切正常。但是,如果我向集合中添加AbilityCardInstance并保存实体,它将与组织一起失败。冬眠错误类异常。我在帖子的底部添加了确切的异常消息。

我通读了一些问题,在处理基类集合时,延迟加载似乎是一个问题,因此,在添加卡片并保存之前,我是如何加载用户实体的:

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

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

共有2个答案

侯池暝
2023-03-14

我解决了这个问题。

根本原因在于这种设计:

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

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

我希望这能帮助那些遇到同样问题的人。

夏侯昆琦
2023-03-14

根据@ManyToOne的JavaDocs第一段:

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

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

修复方法是将Target etEntity=Card.class添加到@ManyToOne。由于Card抽象的并且具有@继承@判别列注释,这会强制Hibernate通过所有可能的方式解析实际的字段类型。它使用Card表的鉴别器值来执行此操作并生成正确的类实例。此外,类型安全保留在Java代码中。

因此,一般来说,每当有可能在运行时无法完全了解字段的类型时,请将targetEntity与manytone和OneToMany一起使用。

 类似资料:
  • 问题: 我是否需要删除接口IAbstractUserService上的泛型? 是否与此答案的类型擦除有关?https://stackoverflow.com/a/31266152/6698175 问题: 我得到了这个例外: <代码>组织。冬眠ErrorClassException:对象[id=1]不属于指定的子类[com.faz.idb.models.advisor]:加载的对象属于错误的com类

  • 我正在尝试将值更新到表中。如果新创建和保存的日期范围id工作正常。但是当试图更新现有日期范围id的值时,它会给我一个错误“org”。冬眠TransientObjectException:对象引用未保存的临时实例-在刷新之前保存临时实例:'。如何更新两种情况下的表值?

  • 我试图在名为Person和Address的两个实体之间建立单向关系,同时保存Person(包含地址集合)获取组织。冬眠TransientObjectException:对象引用未保存的临时实例。 当我更改cascadeType=all时,子对象正在传播。但这里的问题是cascadeType=all Hibernate在删除所属实体时也会尝试删除子实体。我不希望发生这种情况,因为在很多关系中,子实体

  • 我在Hibernate中使用注释。我得到这个错误: 组织。冬眠MappingException:未知实体:xyz。豆在组织进行测试。冬眠实施。SessionFactoryImpl。位于org的getEntityPersister(SessionFactoryImpl.java:550)。冬眠事件def。DefaultLoadEventListener。org上的onLoad(DefaultLoad

  • 初始数据。专业有很多科目。 专业JAVA 对于一个主题来说,专业不能为空。我希望它能以下一种方式工作:当我保存/更新/分离一个主题时,同样的操作必须应用于专业。当我删除一个主题时,专业不会发生任何变化。 主题JAVA 我写了一个集成测试。生成专业()和生成主题()这只是util方法。 你可以在这张图片上看到测试结果。 subjectService在此处引发了异常。保存(主题1); 原因:org。冬

  • 我正在将一个应用程序从Spring 3迁移到Spring 4。特别是,我正在将其迁移到 这是与Spring 3一起使用的原始代码: 在Spring 4中,我将其更新为: 方法中的每一行都成功,并且返回行的结果不为空。但是,当方法退出时会发生异常: org.springframework.transaction.TransactionSystemException:无法提交Hibernate事务;嵌