我有一个使用Hibernate进行数据持久化的应用程序,其中Spring位于顶部(为了更好的衡量标准)。直到最近,应用程序中还有一个持久化类,A:
@Entity
public class A {
@Id
@Column(unique = true, nullable = false, updatable = false)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
public String name;
}
我已经添加了A的子类,名为B:
@Entity
public class B extends A {
public String description;
}
添加B后,我现在无法加载A.引发了以下异常:
class org.springframework.orm.hibernate3.HibernateObjectRetrievalFailureException :: Object with id: 1 was not of the specified subclass: A (Discriminator: null); nested exception is org.hibernate.WrongClassException: Object with id: 1 was not of the specified subclass: A (Discriminator: null)
我在B中添加了以下注释和属性,似乎已经解决了问题。这是解决问题的正确方法吗?
...
@DiscriminatorFormula("(CASE WHEN dtype IS NULL THEN 'A' ELSE dtype END)")
public class A {
private String dtype = this.getClass().getSimpleName();
...
答案 0 :(得分:2)
(...)直到最近,应用程序中还有一个持久化类,A:
使用以下数据库表示:
ID NAME
-- ----
1 foo
2 bar
我已经添加了A的子类,名为B(...)
您没有指定Inheritance
注释,因此使用了SINGLE_TABLE
映射策略。并且在此策略中,层次结构中的所有类都映射到单个表。该表有一个用作“鉴别器列”的列,即一个列,其值标识该行所代表的实例所属的特定子类。
然后桌子变成了:
ID NAME DTYPE
-- ---- -----
1 foo NULL
2 bar NULL
其中DTYPE是用于鉴别器的列的默认名称。
添加B后,我现在无法加载A.引发了以下异常(...)
实际上,由于现有值在discriminator列中具有空值,因此提供程序不知道要实例化的子类。
我在B中添加了以下注释和属性,似乎已经解决了问题。这是解决问题的正确方法吗?
这是一种方式,但它是侵入性的(您的实体不应该知道dtype
列)和Hibernate特定的。换句话说,这是一个黑客。
对我来说,解决这个问题的“正确”方法是更新现有A记录的DTYPE
列,将值设置为'A'
(使用Hibernate时,默认值为实体名称):
UPDATE A SET DTYPE='A' WHERE DTYPE=NULL
这样,Hibernate就能正确加载它们。