org.hibernate.WrongClassException 关于通过 Hibernate 保存实体
org.hibernate.WrongClassException on saving an entity via Hibernate
在这个问题中,我使用的是 Hibernate 4.3.4.Final 和 Spring ORM 4.1.2.RELEASE.
我有一个用户 class,它拥有一组像这样的 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 基础 class 和 CardInstance 基础 class 分别像这样:
@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。我在 post.
的底部添加了确切的异常+消息
我通读了一些问题,延迟加载似乎是处理基集合的问题 class,所以这是我在添加卡片和保存之前加载用户实体的方式:
User user = this.entityManager.createQuery("FROM User u " +
"WHERE u.id = ?1", User.class)
.setParameter(1, id)
.getSingleResult();
Hibernate.initialize(user.getCards());
return user;
"cards"
的数据库条目
"cardinstances"
的数据库条目
org.hibernate.WrongClassException: Object [id=1] was not of the specified subclass [org.gwentonline.model.cards.UnitCard] : Discriminator: leader
提前感谢您提供解决此问题的任何线索。如果您需要更多信息,我很乐意更新我的问题!
我解决了问题。
根本原因在于这个设计:
@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> {
}
在 运行 时 class 的泛型类型的信息在 java 中不存在。有关详细信息,请参阅此问题:Java generics - type erasure - when and what happens
这意味着 hibernate 无法确定 CardInstance
class.
的实际类型
解决这个问题的方法是简单地摆脱通用类型和所有扩展(实现)classes,只使用一个 class 像这样:
@Table
@Entity
@Inheritance
@DiscriminatorColumn(name = "card_type", discriminatorType = DiscriminatorType.STRING)
public class CardInstance {
Card card;
}
这是可能的(而且是更好的设计),因为成员 card
包含有关卡片类型的所有信息。
我希望这对 运行 遇到同样问题的人有所帮助。
根据 first paragraph of the JavaDocs for @ManyToOne
:
It is not normally necessary to specify the target entity explicitly since it can usually be inferred from the type of the object being referenced.
但是,在这种情况下,@ManyToOne
位于类型为泛型的字段上,并且泛型类型信息在编译类型时被删除。因此,在反序列化时,Hibernate 并不知道该字段的确切类型。
修复方法是将 targetEntity=Card.class
添加到 @ManyToOne
。由于 Card
是 abstract
并且具有 @Inheritance
和 @DiscriminatorColumn
注释,这迫使 Hibernate 通过所有可能的方式解析实际字段类型。它使用 Card
table 的鉴别器值来执行此操作并生成正确的 class 实例。另外,类型安全保留在 Java 代码中。
因此,一般来说,只要有可能在运行时不完全知道字段的类型,请将 targetEntity
与 @ManyToOne
和 @OneToMany
一起使用。
在这个问题中,我使用的是 Hibernate 4.3.4.Final 和 Spring ORM 4.1.2.RELEASE.
我有一个用户 class,它拥有一组像这样的 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 基础 class 和 CardInstance 基础 class 分别像这样:
@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。我在 post.
的底部添加了确切的异常+消息我通读了一些问题,延迟加载似乎是处理基集合的问题 class,所以这是我在添加卡片和保存之前加载用户实体的方式:
User user = this.entityManager.createQuery("FROM User u " +
"WHERE u.id = ?1", User.class)
.setParameter(1, id)
.getSingleResult();
Hibernate.initialize(user.getCards());
return user;
"cards"
的数据库条目
"cardinstances"
的数据库条目
org.hibernate.WrongClassException: Object [id=1] was not of the specified subclass [org.gwentonline.model.cards.UnitCard] : Discriminator: leader
提前感谢您提供解决此问题的任何线索。如果您需要更多信息,我很乐意更新我的问题!
我解决了问题。
根本原因在于这个设计:
@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> {
}
在 运行 时 class 的泛型类型的信息在 java 中不存在。有关详细信息,请参阅此问题:Java generics - type erasure - when and what happens
这意味着 hibernate 无法确定 CardInstance
class.
解决这个问题的方法是简单地摆脱通用类型和所有扩展(实现)classes,只使用一个 class 像这样:
@Table
@Entity
@Inheritance
@DiscriminatorColumn(name = "card_type", discriminatorType = DiscriminatorType.STRING)
public class CardInstance {
Card card;
}
这是可能的(而且是更好的设计),因为成员 card
包含有关卡片类型的所有信息。
我希望这对 运行 遇到同样问题的人有所帮助。
根据 first paragraph of the JavaDocs for @ManyToOne
:
It is not normally necessary to specify the target entity explicitly since it can usually be inferred from the type of the object being referenced.
但是,在这种情况下,@ManyToOne
位于类型为泛型的字段上,并且泛型类型信息在编译类型时被删除。因此,在反序列化时,Hibernate 并不知道该字段的确切类型。
修复方法是将 targetEntity=Card.class
添加到 @ManyToOne
。由于 Card
是 abstract
并且具有 @Inheritance
和 @DiscriminatorColumn
注释,这迫使 Hibernate 通过所有可能的方式解析实际字段类型。它使用 Card
table 的鉴别器值来执行此操作并生成正确的 class 实例。另外,类型安全保留在 Java 代码中。
因此,一般来说,只要有可能在运行时不完全知道字段的类型,请将 targetEntity
与 @ManyToOne
和 @OneToMany
一起使用。