JPA 2.0 / Hibernate InheritanceType TABLE_PER_CLASS和OneToMany / ManyToOne双向关系

时间:2013-06-20 19:51:09

标签: java hibernate jpa jpa-2.0

我们有2个表(活动表和存档表),它们具有相同的结构(例如EmployeeEmployeeArchive)。为了能够利用公共代码来为两个表使用结果,我们有一个抽象的父类,它定义了所有的方法和注释。 我们希望能够执行将对两个表使用相同查询并将结果合并在一起的查询。

我们有一个与Organization具有onetomany / manytoone双向关系的另一个实体/表格(例如Employee); OrganizationList Employee个,每个员工都有一个组织。 通过关联获取组织的员工时,我们只希望活动表中的员工不是存档。

有没有办法实现我们的尝试或可行的解决方法?

我们已经尝试了@ MappedSuperclass@Entity / @InheritanceType.TABLE_PER_CLASS的各种实现来尝试实现我们想要的目标。每个实现几乎都会实现我们想要但不完全。例如,为了能够查询这两个表,我们可以使用Entity创建一个抽象的父InheritanceType.TABLE_PER_CLASS,但是mappedByEmployee的{​​{1}}关系不可能Organization }}。我们可以使用MappedSuperclass作为父级来获得正确的关系,但之后我们无法通过联合查询ArchiveActive表。

基本上我们正在尝试布局:

    @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中,但我们得到AnnotationException Organization的关系

    @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)

3 个答案:

答案 0 :(得分:2)

您可以通过更改OrganizationEmployee的映射来实现此目的,以便它使用关系表,而不是在org表中使用Employee字段。请参阅Hibernate documentation中的示例,您可能会看到以下内容:

@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或其他东西)可以更好地处理。然后你没有这些奇怪的抽象类来进行你的查询,多个表有相同类型的数据等等。这个策略的一些描述is here

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

答案 1 :(得分:1)

这是关于hibernate的烦人事情之一。这样做的方法是使用另一个抽象类AbstractMapped,它看起来像这样:

@MappedSuperclass
public abstract class AbstractMapped {

}

然后让AbstractEmployee扩展AbstractMapped。然后你将AbstractEmployee作为Entity和Mapped Superclass,即使这两个标签是互斥的。

答案 2 :(得分:0)

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

组织应包含List<AbstractEmployee>而不是员工。