2017-06-01 77 views
1

我知道similarquestions,但他们被问及在Hibernate的范围内回答。我遇到了同样的问题,但我正在使用Eclipselink,并想知道是否有更好的或替代的解决方案来解决Hibernate的问题。使用Eclipselink/JPA更改实体类型?

回顾一下前不久的问题:

我上课,从相互继承:

@Entity 
@Inheritance(strategy=InheritanceType.SINGLE_TABLE) 
@DiscriminatorColumn(name="dtype") 
@DiscriminatorValue(value="parent") 
public class Parent { 
    @Id 
    private long id; 
} 


@Entity 
@DiscriminatorValue(value="child") 
public class Child extends Parent{ 
    private String childProperty; 
} 

现在我想改变一个孩子到家长或反之亦然,如

Parent p = new Parent(); 
em.persist(p); 

Child c = (Child) p; 
em.merge(c); 

我认为p的数据库行现在是dtype = child

另一种方法是这样的:

Child c = new Child(); 
em.persist(c); 

Parent c = (Parent) c; 
em.merge(c); 

在这种情况下,我希望c被保存dtype = parent和失去childProperty值。

但是,上面所述的内容并不起作用,但我写下来表明我的意思。

有没有办法用Eclipselink做到这一点?

+0

请根据面向对象描述或给出示例代码,了解“更改类型”? –

+0

我扩展了说明 – Bob

+0

看来是不自然的设计,在第一步之后,下一个也是错误的。我不太会说流利的英文来描述如何(以我的理解)解决问题 –

回答

2

如果您想将某个对象从一种类型更改为另一种类型,那么java或JPA继承就没有简单的解决方案。您必须复制您的实例,去掉旧的,然后坚持新的一个是JPA/Java的兼容:

Child c = em.find(pk, Child.class); 
Parent p = new Parent(); 
p.setId(c.getId()); 
p.setOtherFields(c.getOtherFields()); 

em.getTransaction().begin(); 
em.remove(c); 
em.getTransaction().commit(); 
em.clear(); 
em.getTransaction().begin(); 
em.persist(p); 
em.getTransaction().commit(); 

使用相同的交易,这一切“可能”工作在使用冲洗,而不是提交/开始,但不能保证二次缓存的管理变得棘手。另请注意,所有与子项的关系都需要更新以指向“新”父实例,否则缓存将被损坏。

虽然我不太确定这一点,因为在这种情况下,子项是父项实例。除了数据库中的任意标志之外,这种方法没有什么可以获得的。如果您希望可以随时更改,那么使用Java子类可能不适合您的应用程序。

相反,我建议使用一个通用的人,有字段,您可以设置为保持子/父状态。但是,因为一个孩子可以同时成为父母。

+0

谢谢你的回答。我遇到的这个解决方案的一个问题是'em.remove(c);'也会通过cascade-persist删除OneToMany相关的对象。你知道任何方法(除了删除cascade-persist),因为我需要在新的父对象上的OneToMany-Objects。 – Bob

+0

将它们排除。无论如何您都需要清理任何引用,然后将这些引用添加到新实例中。这不幸的是包括修复双向引用,并且由于需要额外的语句,所以不会是最有效的方法。如果您没有使用共享缓存,则可以跳过修复远程引用以指向新实例,但将来限制应用程序。 – Chris