JPA 2.0 / Hibernate 继承类型 TABLE_PER_CLASS 和 OneToMany/ManyToOne 双向关系

4
我们有两张表(一个活动表和一个归档表),它们具有相同的结构(例如EmployeeEmployeeArchive)。为了能够利用共同的代码来使用两个表的结果,我们有一个抽象的父类,定义了所有的方法和注释。我们希望能够执行查询,同时使用两个表相同的查询,并将结果合并在一起。
我们有另一个实体/表(例如Organization),它与Employee具有onetomany/manytoone双向关系;Organization拥有Employee列表,每个员工都属于一个组织。当通过关联获取组织的员工时,我们只想要来自活动表而不是归档表的员工。
是否有方法可以实现我们所尝试的内容或者一个可行的解决方案?
我们已经尝试过各种@MappedSuperclass@Entity/@InheritanceType.TABLE_PER_CLASS的实现来达到我们的目标。每个实现都接近我们想要的,但却无法完全实现。例如,为了能够查询两个表,我们可以使用带有InheritanceType.TABLE_PER_CLASS的抽象父Entity,但是在Organization中就无法有mappedBy关系到Employee。我们可以使用一个MappedSuperclass作为父类来拥有正确的关系,但是这样我们就无法通过联合查询两个表了。
以下是我们基本上要布局的内容:
    @Entity
    @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
    public abstract class AbstractEmployee {
        @ManyToOne
        @JoinColumn(name="employeeId", nullable=false)
        Organization org;
        ...
    }

    @Entity
    public class Employee extends AbstractEmployee {
    }

    @Entity
    public class EmployeeArchive extends AbstractEmployee {
    }

    @Entity
    public class Organization {
       @OneToMany(cascade=ALL, mappedBy="org")
       List<Employee> employees;         
       ...            
    }

代码

    public List<AbstractEmployee> getAllEmployees()
    {
       Query query = em.createQuery("SELECT e FROM AbstractEmployee e where e.name = ‘John’", AbstractEmployee.class);
       return query.getResultList();
    }

    public List<Organization> getOrganizations()
    {
       Query query = em.createQuery("SELECT e FROM Organization o ", Organization.class);
       List<Organization> orgs = query.getResultList();
       // fetch or eager fetch the Employees but only get the ones from the active employee table
       return orgs;
    }

我们还尝试让父类扩展MappedSuperclass,并将实现和注释放在MappedSuperclass中,但是我们为Organization的关系获得了AnnotationException

    @MappedSuperclass
    public abstract class AbstractMapped {
        @ManyToOne
        @JoinColumn(name="employeeId", nullable=false)
        Organization org;
    }

    @Entity
    @Inheritance(@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS))
    public abstract class AbstractEmployee extends AbstractMapped {
        ... `Constructors` ...
    }

在部署时,我们遇到了以下异常:

    Caused by org.hibernate.AnnotationException: mappedBy reference an unknown target entity property: Employee.org in Organizaztion.employees
       at org.hibernate.cfg.annotations.CollectionBinder.bindStarToManySecondPass(CollectionBinder.java:685)

我有一个类似的问题。你愿意帮我吗?这是链接:https://dev59.com/doLba4cB1Zd3GeqPd2N2 - CodeMed
3个回答

2
你可以通过将OrganizationEmployee之间的映射更改为使用关系表来实现,而不是在Employee表中拥有org字段。请参考Hibernate文档中的示例,对你来说应该是这样的:
@Entity
public class Organization {
   @OneToMany(cascade=ALL)
   @JoinTable(
        name="ACTIVE_EMPLOYEES",
        joinColumns = @JoinColumn( name="ORGANIZATION_ID"),
        inverseJoinColumns = @JoinColumn( name="EMPLOYEE_ID")
   )
   List<Employee> employees;         
   ...            
}

然而,我必须说,我认为使用两个表来表示当前的与归档的员工是一个不好的想法。这对我来说听起来像一种“软删除”的情况,最好使用表内标志(IS_ACTIVE或其他)来处理。这样你就不需要使用这些奇怪的抽象类来查询数据,也不需要使用相同类型的多个表等等。这种策略的一些描述在这里

然后,您可以使用已经拥有的非连接表映射,并使用@Where注释来将组织中的员工限制为已将IS_ACTIVE设置为true的员工。这种方法的一个例子在这里


你的解决方案更加明智!我喜欢它 +1 - Mihai Soloi
谢谢sharakan,联合表映射看起来似乎可以解决问题(还没有尝试过)。数据库策略有点超出我的控制范围,但我会进行一些讨论,看看是否可能使用不同的“软删除”策略,例如只设置一个归档标志或将所有数据放入归档表/数据库中,这样我们就不必担心查询两个表了。 - bdrx

1
这是 Hibernate 中令人烦恼的事情之一。要实现这个功能,需要有另一个抽象类 AbstractMapped,它看起来就像这样:
@MappedSuperclass
public abstract class AbstractMapped {

}

然后让AbstractEmployee扩展AbstractMapped。这样,AbstractEmployee既是实体(Entity)又是映射超类(Mapped Superclass),即使这两个标签是互斥的。

我应该在帖子中提到,我们已经尝试过那个方法,但没有成功。我们在初始化持久性单元时遇到了异常。我会更新问题。 - bdrx

0

AbstractEmployee 应该是 @MappedSuperClass,而不应该是 @Entity,这会为该类创建一个表。

Organization 应该包含一个 List<AbstractEmployee> 而不是 Employee。


如果组织包含一个 List<AbstractEmployee>,那么关系检索将查询两个表,即存档和活动表,这正是我们想要避免的。我们不希望查询组织的员工时查询存档表。 - bdrx

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接