代码之家  ›  专栏  ›  技术社区  ›  Armand

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

  •  5
  • Armand  · 技术社区  · 14 年前

    我有一个使用Hibernate实现数据持久化的应用程序,上面有Spring(这是一个很好的方法)。直到最近,应用程序中还存在一个持久类,即:

    @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 回复  |  直到 14 年前
        1
  •  2
  •   Pascal Thivent    14 年前

    (…)直到最近,应用程序中还有一个持久类,即:

    ID  NAME
    --  ----
     1   foo
     2   bar
    

    从那以后,我添加了a的一个子类,称为B(…)

    但你没有说明 Inheritance SINGLE_TABLE 采用映射策略。以及 在这个策略中,层次结构中的所有类都映射到一个表。该表有一个列用作鉴别器列,也就是说,该列的值标识由行表示的实例所属的特定子类。

    ID  NAME DTYPE
    --  ---- -----
     1   foo  NULL
     2   bar  NULL
    

    实际上,因为现有值在discriminator列中有一个空值,所以提供程序不知道实例化哪个子类。

    我为B添加了以下注释和属性,似乎解决了这个问题。这是解决问题的正确方法吗?

    这是一种方式,但它是侵入性的(您的实体不应该意识到 dtype 列)和休眠特定。换句话说,这是一个黑客。

    对我来说,解决这个问题的“正确”方法是更新 DTYPE 'A'

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

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