2010-08-02 102 views
5

我有一个应用程序使用Hibernate的数据持久性,与顶部的弹簧(好措施)。直到最近,有一个持久化类的应用,A:使用DiscriminatorFormula迁移Hibernate数据库是不好的做法吗?

@Entity 
public class A { 
    @Id 
    @Column(unique = true, nullable = false, updatable = false) 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    private long id; 
    public String name; 
} 

因为我已经添加了一个子类,称为B:

@Entity 
public class B extends A { 
    public String description; 
} 

加入B之后,我现在可以不加载的。抛出以下异常:

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(); 
    ... 

回答

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特定。换句话说,这是一个黑客。

对于我来说,“正确”的方式来解决,这将是更新现有的A记录的值设置为'A'(与Hibernate,则默认值为实体名称)的DTYPE列:

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

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

+0

感谢您的详细解答。不幸的是,我不会直接访问应用程序的所有安装,所以我希望这种模式更改对用户透明。我尝试添加DiscriminatorFormula而没有明确定义dtype字段,但是这不起作用。当我这样做的时候感觉像是一个黑客 - 这就是为什么我问。 – Armand 2010-08-03 08:48:12

+1

@Alison不客气。我给你什么是IMO的“理想”解决方案。如果它不适合你的上下文,如果你不能为你的用户提供一个迁移脚本(这将在各种“ALTER”之后执行'UPDATE'),或者甚至是更好的自动迁移工具 - 那么你的解决方案是可以接受的。至少它工作。而现在你知道它有点破解:) – 2010-08-03 09:19:02

+0

- )我发现在Hibernate/Spring中迁移的信息相当难以处理,不幸的是。 – Armand 2010-08-03 12:40:31