5

我有一个使用 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();
    ...
4

1 回答 1

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。引发了以下异常 (...)

实际上,因为现有值在鉴别器列中有一个空值,所以提供者不知道要实例化哪个子类。

我在B中添加了如下注解和属性,似乎解决了问题。这是解决问题的正确方法吗?

这是一种方式,但它是侵入性的(您的实体不应该知道该dtype列)并且特定于 Hibernate。换句话说,这是一个黑客。

对我来说,解决这个问题的“正确”方法是更新DTYPE现有 A 记录的列以将值设置为'A'(使用 Hibernate,该值默认为实体名称):

UPDATE A SET DTYPE='A' WHERE DTYPE=NULL

这样,Hibernate 将能够正确加载它们。

于 2010-08-03T04:12:16.007 回答