在这个问题中,我正在使用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 user = this.entityManager.createQuery("FROM User u " +
"WHERE u.id = ?1", User.class)
.setParameter(1, id)
.getSingleResult();
Hibernate.initialize(user.getCards());
return user;
&#34;卡&#34;的数据库条目
&#34; cardinstances&#34;的数据库条目
org.hibernate.WrongClassException: Object [id=1] was not of the specified subclass [org.gwentonline.model.cards.UnitCard] : Discriminator: leader
提前感谢任何线索如何解决此问题。如果您需要其他信息,我很乐意更新我的问题!
答案 0 :(得分:5)
根据first paragraph of the JavaDocs for @ManyToOne
:
通常不需要明确指定目标实体,因为它通常可以从被引用对象的类型推断出来。
但是,在您的情况下,Value
位于字段类型为通用的字段上,泛型类型信息将在编译类型中被删除。因此,在反序列化时,Hibernate不知道该字段的确切类型。
修复方法是将@ManyToOne
添加到targetEntity=Card.class
。由于@ManyToOne
为Card
并且具有abstract
和@Inheritance
注释,因此强制Hibernate通过所有可能的方式解析实际字段类型。它使用@DiscriminatorColumn
表的鉴别器值来执行此操作并生成正确的类实例。另外,您在Java代码中保留了类型安全性。
因此,通常情况下,只要有可能在运行时未完全了解字段的类型,请将Card
与targetEntity
和@ManyToOne
一起使用。
答案 1 :(得分: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 generics - type erasure - when and what happens
这意味着hibernate无法确定CardInstance
类的实际类型。
解决这个问题的方法就是删除泛型类和所有扩展(实现)类,只使用这样一个类:
@Table
@Entity
@Inheritance
@DiscriminatorColumn(name = "card_type", discriminatorType = DiscriminatorType.STRING)
public class CardInstance {
Card card;
}
这是可能的(并且通过更好的设计),因为成员card
包含有关卡类型的所有信息。
我希望如果他们遇到同样的问题,这可以帮助民众。