JPA EntityManager finder方法返回其他子类对象

时间:2017-04-30 05:04:18

标签: jpa ejb-3.1

我遇到了JPA EntityManager finder方法的问题。 JPA实体使用继承结构如下:

//Need to persist this table to database
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
@Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL)
@Table(name="Table1")
public class BaseEntity implements Serializable {
    @Id
    @Column(name="PRIMARY_ID")
    private long id;
    private String field1;
    .......
}

//This table will NOT persist and has parameters only for Sub classs
    @MappedSuperclass
    public abstract class MappedSuperClassEntity extends BaseEntity  {

      private String field2;
      private String field3;
      ........
    }

//This sub class is persisted and inherits fields form above class including Primary Key using TABLE_PER_CLASS strategy defined in BaseEntity
    @Entity
    @Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL)
    @Table(name="SubTable1")
    public class Sub1 extends MappedSuperClassEntity {
      private String field4;
      private String field5;
      ...............     
    }

//This sub class is persisted and inherits fields form above class including Primary Key using TABLE_PER_CLASS strategy defined in BaseEntity   
    @Entity
    @Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL)
    @Table(name="SubTable2")
    public class Sub2 extends MappedSuperClassEntity {
      private String field4;
      private String field5;
      ..............      
    }

正如你所看到的,Sub1和Sub2是可持久的entites,它们都扩展了MappedSuperClassEntity,它用`@MappedSuperClass'注释。该类进一步继承了BaseEntity,它描述了TABLE_PER_CLASS继承策略。

我启用了hibernate stat收集器,发现hibernate使用Parent类的键存储子类对象。因此,在上面的例子中,它为Sub1 finder在缓存中存储如下数据:

14:17:03,941 DEBUG [org.hibernate.cache.TransactionalCache]缓存查找:com.abc.BaseEntity#10 14:17:03,943 DEBUG [org.hibernate.cache.TransactionalCache]缓存未命中 14:17:03,948 DEBUG [org.hibernate.cache.TransactionalCache]缓存:com.abc.BaseEntity#10

下次如果我为同一个id(10)查找Sub2,hibernate认为它在Cache中,因为它使用Parent Class作为键并返回Sub1对象,如下所示:

14:27:54,574 DEBUG [org.hibernate.cache.TransactionalCache]缓存查找:com.abc.BaseEntity#10 14:27:54,575 DEBUG [org.hibernate.cache.TransactionalCache]缓存命中

当您运行Sub1和Sub2的查找程序时,会发生这种情况:

entityManager.find(Sub1.class, id);   //returns Sub1 object
entityManager.find(Sub2.class, id);   //returns Sub1 object (PROBLEM HERE).

请帮我修复问题(我不想在这些调用之间清除缓存)

1 个答案:

答案 0 :(得分:0)

问题是你在使用基本实体时没有意义。当您从基本实体继承而不仅仅是从映射的超类继承时,您不仅仅是继承字段和方法。您正在建立关系。

一个有意义的例子如下:Car和Bike都继承了一个基本实体Vehicle。在这种情况下,Car实体是Vehicle实体。 Bike实体是Vehicle实体。

如果汽车的ID为42,那么自行车也可以拥有ID 42,因为您将拥有两辆具有相同ID的车辆。想象一下具有与车辆的ManyToOne关联的驾驶员实体(即驾驶员驾驶车辆)。如果我将ID 42存储在驱动程序表的vehicle_id列中,则该ID 42必须唯一地识别车辆。它可能是一辆汽车,它可能是一辆自行车,而hibernate将会在两个表中看到,但它不能同时出现。

你违反了这种继承概念。不应使用Entity注释BaseEntity。它应该只是一个MappedSuperclass,它只允许继承字段和方法,但不会建立这种语义关联。