我们有2个表(活动表和存档表),它们具有相同的结构(例如Employee
和EmployeeArchive
)。为了能够利用公共代码来为两个表使用结果,我们有一个抽象的父类,它定义了所有的方法和注释。
我们希望能够执行将对两个表使用相同查询并将结果合并在一起的查询。
我们有一个与Organization
具有onetomany
/ manytoone
双向关系的另一个实体/表格(例如Employee
); Organization
有List
Employee
个,每个员工都有一个组织。
通过关联获取组织的员工时,我们只希望活动表中的员工不是存档。
有没有办法实现我们的尝试或可行的解决方法?
我们已经尝试了@ MappedSuperclass
,@Entity
/ @InheritanceType.TABLE_PER_CLASS
的各种实现来尝试实现我们想要的目标。每个实现几乎都会实现我们想要但不完全。例如,为了能够查询这两个表,我们可以使用Entity
创建一个抽象的父InheritanceType.TABLE_PER_CLASS
,但是mappedBy
中Employee
的{{1}}关系不可能Organization
}}。我们可以使用MappedSuperclass
作为父级来获得正确的关系,但之后我们无法通过联合查询Archive
和Active
表。
基本上我们正在尝试布局:
@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)
答案 0 :(得分:2)
您可以通过更改Organization
到Employee
的映射来实现此目的,以便它使用关系表,而不是在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>
而不是员工。