使用DiscriminatorFormula迁移Hibernate数据库是不好的做法吗?

时间:2010-08-02 15:23:54

标签: java hibernate persistence orm table-per-hierarchy

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

1 个答案:

答案 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就能正确加载它们。