Hibernate Table 每个子类方法 - mappedBy 引用未知目标实体 属性
Hibernate Table per Subclass approach - mappedBy reference an unknown target entity property
我有一个像
这样的 table 层次结构
Job{jobId, title} 与
具有一对多关系
Task{taskId, jobId(FK), task_title} 与一对多关系
SubTask{subTaskId, TaskId(FK), subtask_title}。
现在我有一个 table 的子集,它扩展了 table 上面的主要 table,例如
TechinalJob{jobId(FK), Technical_Details},
TechinalTask{taskId(FK), Technical_Task_Details},
TechinalSubTask{subTaskId(FK), Technical_SubTask_Details}。
同样,我将有管理 Jobs/Tasks/SubTasks。
但问题是我在技术 Jobs/Tasks/SubTasks 或管理之间没有关系。关系是通过原始 Job/Task/SubTask 建立的。我在 Techincal Jobs/Tasks/SubTasks 或管理主键中也没有主键。因此,如果我必须在 TechinalJob 和 TechincalTask 之间创建双向一对多关系,我必须通过 Job/Task/SubTask table 结构执行以下操作。我如何使用 Hibernate 继承来实现这一点。
2015 年 3 月 25 日更新:
尝试Zielu建议的ver2后。这是修改后的代码
@Entity
@Table(name = "Job")
@Inheritance(strategy=InheritanceType.JOINED)
public class Job {
@Id
private int jobId;
@OneToMany(mappedBy="job")
protected Set<? extends Task> tasks;
public Set<? extends Task> getTasks(
return tasks;
);
}
@Entity
@Table(name = "Task")
@Inheritance(strategy=InheritanceType.JOINED)
public class Task {
@Id
private int taskId;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "jobId", updatable=false, insertable=false)
public Job job;
public Job getJob() {
return job;
}
public void setJob(Job job) {
this.job= job;
}
}
@Entity
@Table(name = "TechinalJob")
@PrimaryKeyJoinColumn(name="jobId")
public class TechincalJob extends Job {
@OneToMany(mappedBy="job")
Set<TechincalTask> tasks;
@Override
public Set<TechnicalTask> getTasks() {
return (Set<TechnicalTask>)tasks;
};
@Column(name="Technical_Details")
private Integer Technical_Details;
}
@Entity
@Table(name = "TechincalTask")
@PrimaryKeyJoinColumn(name="taskId")
public class TechincalTask extends Task {
public TechincalJob getJob() {
return (TechincalJob)job;
}
@Column(name="Technical_Task_Details")
private Integer Technical_Task_Details;
}
当我尝试这个时我得到一个异常说 Caused by: org.hibernate.AnnotationException: mappedBy reference an unknown target entity 属性: TechinalTask.job in TechincalJob.tasks。尽管我正在扩展 Task 并确保 Task 中的工作是 public.
,但它无法在 TechnicalTask 中找到工作
提前致谢..
这取决于您要实现的目标。
你提到在DB中扩展tables,但是在SQL中没有像subtables这样的东西,这是Java的概念,所以让我们看一下从 Java 点开始。如果我写了一些对你来说显而易见的事情,请提前道歉(最接近你的解决方案的是第 1 点的末尾)。
- 您有工作及其子class。每个作业都有任务列表。任务也有它的子classes。 TechnicalJobs 中总是有 TechnicalTask。
所以你会有代码:
//ver1
class Job {
public abstract Set<? extends Task> getTasks();
}
class TechnicalJob extends Job {
Set<TechnicalTask> tasks = new HashSet<>();
@Override
public Set<TechnicalTask> getTasks() {
return tasks;
};
}
或
//ver2
class Job {
Set<? extends Task> tasks = new HashSet<>();
public Set<? extends Task> getTasks(
return tasks;
);
}
class TechnicalJob extends Job {
@Override
public Set<TechnicalTask> getTasks() {
return (Set<TechnicalTask>)tasks;
};
}
你会像这样使用它:
TechnicalJob tj = ...;
Job jn = jt;
for (Task t : jn.getTasks()) t.doSomething();
for (TechnicalTask t: jt.getTasks()) t.doSomethingTechnical();
现在,您提到的数据库结构看起来更像 ver2,您在 table 中有任务的关系列,它将 "translate" 到作业中的 Set<> 任务字段(您可以定义了一个连接 table JobTask 而不是它完全等同于 tasks 字段)。
所以你不需要在你的子工作、子任务中进行额外的映射。简单:
@Entity
@Table(name = "Job")
@Inheritance(strategy=InheritanceType.JOINED)
public class Job {
@Id
@GeneratedValue(strategy = GenerationType.TABLE)
int jobId;
@OneToMany(mappedBy="job")
Set<Task> tasks;
public Set<? extends Task> getTasks() {
if (tasks == null) tasks = new HashSet<>();
return tasks;
}
}
@Entity
@Table(name = "TechinalJob")
public class TechinalJob extends Job {
@Override
public Set<TechincalTask> getTasks() {
return (Set<TechincalTask>)super.getTasks();
}
}
您通过类型访问方法提供类型安全(只有 TechnicalTasks
进入 TechnicalJo
b),例如 TechnicalJob
中的 addTask(TechnicalTask task)
。它模仿您的数据库结构,其中没有什么能阻止您在链接到 TechnicalJob 的任务 table 中拥有一行,但它也与管理任务中的记录相结合,因此它不是真正的 TechnicalTask。
如果你负责模式,因为你已经在使用继承策略 JOIN,你可以考虑使用 Ver1 方法,所以 Job/Task class 中没有映射(仅抽象 getter) .并映射到单个子 classes 中。这将提供更好的类型控制,但 joinColumn 将在 Task subtables.
中
@Entity
@Table(name = "Job")
@Inheritance(strategy=InheritanceType.JOINED)
public abstract class Job {
@Id
@GeneratedValue(strategy = GenerationType.TABLE)
int jobId;
public abstract Set<? extends Task> getTasks();
}
@Entity
@Table(name = "Task")
@Inheritance(strategy=InheritanceType.JOINED)
public class Task {
@Id
@GeneratedValue(strategy = GenerationType.TABLE)
int taskId;
}
@Entity
@Table(name = "TechinalJob")
@PrimaryKeyJoinColumn(name="jobId")
public class TechinalJob extends Job {
@OneToMany(mappedBy="job")
Set<TechincalTask> tasks;
}
@Entity
@Table(name = "TechincalTask")
public class TechincalTask extends Task {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "jobId")
TechinalJob job;
}
最后在它的基础上构建,与您尝试实现的最接近的匹配 == 任务中的 joinColumn table,特定作业中的任务子类型。任务映射到作业,但作业不映射到任务只有子作业有映射:
@Entity
@Table(name = "Job")
@Inheritance(strategy=InheritanceType.JOINED)
public abstract class Job {
@Id
@GeneratedValue(strategy = GenerationType.TABLE)
int jobId;
public abstract Set<? extends Task> getTasks();
}
@Entity
@Table(name = "TechinalJob")
@PrimaryKeyJoinColumn(name="jobId")
public class TechinalJob extends Job {
@OneToMany(mappedBy="job") //you need the mapped by, it was missing in your code
Set<TechincalTask> tasks;
@Column(name="Technical_Details")
Integer Technical_Details;
@Override
public Set<TechincalTask> getTasks() {
if (tasks == null) tasks = new HashSet<>();
return tasks;
}
}
@Entity
@Table(name = "Task")
@Inheritance(strategy=InheritanceType.JOINED)
public class Task {
@Id
@GeneratedValue(strategy = GenerationType.TABLE)
int taskId;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "jobId")
Job job;
}
@Entity
@Table(name = "TechincalTask")
@PrimaryKeyJoinColumn(name="taskId")
public class TechincalTask extends Task {
//you don't define relationship to Job it comes from the parrent
@Column(name="Technical_Task_Details")
Integer Technical_Task_Details;
public TechnicalJob getJob() {
return (TechnicalJob)job;
}
编辑
上面的代码 适用于 EclipseLink 但不适用于 Hibernate。正如 Adithye 注意到的那样,异常是由于缺少映射目标而抛出的。
- 您有作业及其子类,每个作业都有任务列表,每个子作业都有常规任务列表和另一个专门任务列表,例如 TechnicalTasks。您的 Java 代码有点像 Job 有 Taks 而 TechnicalJobs 有 Tasks(继承自 Job)和它自己的 technicalTasks 集合。
在那种情况下,它们必须映射到不同的连接 table,否则两个集合将拥有相同的值。
谢谢 Zielu,我感谢你为帮助我所做的一切努力。我终于找到了解决方案。但它不是通过休眠继承。我使用了 SecondaryTable 和 java 继承的组合。我这样做的方法是创建超类 @MappedSuperClass 并使子对象使用父类的 table 作为 @Table 和子类的 table 作为 @SecondaryTable
@MappedSuperClass
public class Job <J extends Job, T extends Task,> {
@Id
private int jobId;
@OneToMany(mappedBy="job")
protected Set<T> tasks;
public Set<T> getTasks(
return tasks;
);
}
@MappedSuperClass
public class Task <T extends Task, J extends Job> {
@Id
private int taskId;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "jobId", updatable=false, insertable=false)
public J job;
public J getJob() {
return job;
}
}
@Entity
@Table("Job")
@SecondaryTable("TechinalJob")
public class TechnicalJob extends Job<TechnicalJob, TechnicalTask> {
//get all relations from parent and additional columns
}
@Entity
@Table("Task")
@SecondaryTable("TechinalTask")
public class TechnicalTask extends Task<TechnicalTask, TechnicalJob> {
//get all relations from parent and additional columns
}
并为 Task 和 TechnicalTask 编写一个通用查询,我打算使用 Criteria。在我的 DAO 中,我会有类似
的东西
public class JobDAO <J extends Job> {
protected Class<? extends Job> jobClass = Job.class;
public List<J> getJobs(int id) {
return (List<T>)(entityManager.unwrap(Session.class)).createCriteria(jobClass, "j").list();
}
}
public class TaskDAO <T extends Task> {
public List<T> getTasks
}
public class TechnicalJobDAO extends JobDAO<TechnicalJob> {
@PostConstruct
public void init() {
jobClass = TechnicalJob.class;
}
//get all parents methods
}
public class TechnicalTaskDAO extends TaskDAO<TechnicalTaskk> {
//get all parents methods
}
hibernate 中的隐式多态性是我不去使用 HQL 查询的另一个原因,尽管它们很优雅。现在我正在放弃直接查询 Job 和 Task,但是由于隐式多态性,即使我使用 Hibernate Table 每个子类继承也是行不通的。
谢谢..
我有一个像
这样的 table 层次结构Job{jobId, title} 与
具有一对多关系Task{taskId, jobId(FK), task_title} 与一对多关系
SubTask{subTaskId, TaskId(FK), subtask_title}。
现在我有一个 table 的子集,它扩展了 table 上面的主要 table,例如
TechinalJob{jobId(FK), Technical_Details},
TechinalTask{taskId(FK), Technical_Task_Details},
TechinalSubTask{subTaskId(FK), Technical_SubTask_Details}。
同样,我将有管理 Jobs/Tasks/SubTasks。
但问题是我在技术 Jobs/Tasks/SubTasks 或管理之间没有关系。关系是通过原始 Job/Task/SubTask 建立的。我在 Techincal Jobs/Tasks/SubTasks 或管理主键中也没有主键。因此,如果我必须在 TechinalJob 和 TechincalTask 之间创建双向一对多关系,我必须通过 Job/Task/SubTask table 结构执行以下操作。我如何使用 Hibernate 继承来实现这一点。
2015 年 3 月 25 日更新:
尝试Zielu建议的ver2后。这是修改后的代码
@Entity
@Table(name = "Job")
@Inheritance(strategy=InheritanceType.JOINED)
public class Job {
@Id
private int jobId;
@OneToMany(mappedBy="job")
protected Set<? extends Task> tasks;
public Set<? extends Task> getTasks(
return tasks;
);
}
@Entity
@Table(name = "Task")
@Inheritance(strategy=InheritanceType.JOINED)
public class Task {
@Id
private int taskId;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "jobId", updatable=false, insertable=false)
public Job job;
public Job getJob() {
return job;
}
public void setJob(Job job) {
this.job= job;
}
}
@Entity
@Table(name = "TechinalJob")
@PrimaryKeyJoinColumn(name="jobId")
public class TechincalJob extends Job {
@OneToMany(mappedBy="job")
Set<TechincalTask> tasks;
@Override
public Set<TechnicalTask> getTasks() {
return (Set<TechnicalTask>)tasks;
};
@Column(name="Technical_Details")
private Integer Technical_Details;
}
@Entity
@Table(name = "TechincalTask")
@PrimaryKeyJoinColumn(name="taskId")
public class TechincalTask extends Task {
public TechincalJob getJob() {
return (TechincalJob)job;
}
@Column(name="Technical_Task_Details")
private Integer Technical_Task_Details;
}
当我尝试这个时我得到一个异常说 Caused by: org.hibernate.AnnotationException: mappedBy reference an unknown target entity 属性: TechinalTask.job in TechincalJob.tasks。尽管我正在扩展 Task 并确保 Task 中的工作是 public.
,但它无法在 TechnicalTask 中找到工作提前致谢..
这取决于您要实现的目标。
你提到在DB中扩展tables,但是在SQL中没有像subtables这样的东西,这是Java的概念,所以让我们看一下从 Java 点开始。如果我写了一些对你来说显而易见的事情,请提前道歉(最接近你的解决方案的是第 1 点的末尾)。
- 您有工作及其子class。每个作业都有任务列表。任务也有它的子classes。 TechnicalJobs 中总是有 TechnicalTask。
所以你会有代码:
//ver1
class Job {
public abstract Set<? extends Task> getTasks();
}
class TechnicalJob extends Job {
Set<TechnicalTask> tasks = new HashSet<>();
@Override
public Set<TechnicalTask> getTasks() {
return tasks;
};
}
或
//ver2
class Job {
Set<? extends Task> tasks = new HashSet<>();
public Set<? extends Task> getTasks(
return tasks;
);
}
class TechnicalJob extends Job {
@Override
public Set<TechnicalTask> getTasks() {
return (Set<TechnicalTask>)tasks;
};
}
你会像这样使用它:
TechnicalJob tj = ...;
Job jn = jt;
for (Task t : jn.getTasks()) t.doSomething();
for (TechnicalTask t: jt.getTasks()) t.doSomethingTechnical();
现在,您提到的数据库结构看起来更像 ver2,您在 table 中有任务的关系列,它将 "translate" 到作业中的 Set<> 任务字段(您可以定义了一个连接 table JobTask 而不是它完全等同于 tasks 字段)。
所以你不需要在你的子工作、子任务中进行额外的映射。简单:
@Entity
@Table(name = "Job")
@Inheritance(strategy=InheritanceType.JOINED)
public class Job {
@Id
@GeneratedValue(strategy = GenerationType.TABLE)
int jobId;
@OneToMany(mappedBy="job")
Set<Task> tasks;
public Set<? extends Task> getTasks() {
if (tasks == null) tasks = new HashSet<>();
return tasks;
}
}
@Entity
@Table(name = "TechinalJob")
public class TechinalJob extends Job {
@Override
public Set<TechincalTask> getTasks() {
return (Set<TechincalTask>)super.getTasks();
}
}
您通过类型访问方法提供类型安全(只有 TechnicalTasks
进入 TechnicalJo
b),例如 TechnicalJob
中的 addTask(TechnicalTask task)
。它模仿您的数据库结构,其中没有什么能阻止您在链接到 TechnicalJob 的任务 table 中拥有一行,但它也与管理任务中的记录相结合,因此它不是真正的 TechnicalTask。
如果你负责模式,因为你已经在使用继承策略 JOIN,你可以考虑使用 Ver1 方法,所以 Job/Task class 中没有映射(仅抽象 getter) .并映射到单个子 classes 中。这将提供更好的类型控制,但 joinColumn 将在 Task subtables.
中@Entity
@Table(name = "Job")
@Inheritance(strategy=InheritanceType.JOINED)
public abstract class Job {
@Id
@GeneratedValue(strategy = GenerationType.TABLE)
int jobId;
public abstract Set<? extends Task> getTasks();
}
@Entity
@Table(name = "Task")
@Inheritance(strategy=InheritanceType.JOINED)
public class Task {
@Id
@GeneratedValue(strategy = GenerationType.TABLE)
int taskId;
}
@Entity
@Table(name = "TechinalJob")
@PrimaryKeyJoinColumn(name="jobId")
public class TechinalJob extends Job {
@OneToMany(mappedBy="job")
Set<TechincalTask> tasks;
}
@Entity
@Table(name = "TechincalTask")
public class TechincalTask extends Task {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "jobId")
TechinalJob job;
}
最后在它的基础上构建,与您尝试实现的最接近的匹配 == 任务中的 joinColumn table,特定作业中的任务子类型。任务映射到作业,但作业不映射到任务只有子作业有映射:
@Entity
@Table(name = "Job")
@Inheritance(strategy=InheritanceType.JOINED)
public abstract class Job {
@Id
@GeneratedValue(strategy = GenerationType.TABLE)
int jobId;
public abstract Set<? extends Task> getTasks();
}
@Entity
@Table(name = "TechinalJob")
@PrimaryKeyJoinColumn(name="jobId")
public class TechinalJob extends Job {
@OneToMany(mappedBy="job") //you need the mapped by, it was missing in your code
Set<TechincalTask> tasks;
@Column(name="Technical_Details")
Integer Technical_Details;
@Override
public Set<TechincalTask> getTasks() {
if (tasks == null) tasks = new HashSet<>();
return tasks;
}
}
@Entity
@Table(name = "Task")
@Inheritance(strategy=InheritanceType.JOINED)
public class Task {
@Id
@GeneratedValue(strategy = GenerationType.TABLE)
int taskId;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "jobId")
Job job;
}
@Entity
@Table(name = "TechincalTask")
@PrimaryKeyJoinColumn(name="taskId")
public class TechincalTask extends Task {
//you don't define relationship to Job it comes from the parrent
@Column(name="Technical_Task_Details")
Integer Technical_Task_Details;
public TechnicalJob getJob() {
return (TechnicalJob)job;
}
编辑 上面的代码 适用于 EclipseLink 但不适用于 Hibernate。正如 Adithye 注意到的那样,异常是由于缺少映射目标而抛出的。
- 您有作业及其子类,每个作业都有任务列表,每个子作业都有常规任务列表和另一个专门任务列表,例如 TechnicalTasks。您的 Java 代码有点像 Job 有 Taks 而 TechnicalJobs 有 Tasks(继承自 Job)和它自己的 technicalTasks 集合。
在那种情况下,它们必须映射到不同的连接 table,否则两个集合将拥有相同的值。
谢谢 Zielu,我感谢你为帮助我所做的一切努力。我终于找到了解决方案。但它不是通过休眠继承。我使用了 SecondaryTable 和 java 继承的组合。我这样做的方法是创建超类 @MappedSuperClass 并使子对象使用父类的 table 作为 @Table 和子类的 table 作为 @SecondaryTable
@MappedSuperClass
public class Job <J extends Job, T extends Task,> {
@Id
private int jobId;
@OneToMany(mappedBy="job")
protected Set<T> tasks;
public Set<T> getTasks(
return tasks;
);
}
@MappedSuperClass
public class Task <T extends Task, J extends Job> {
@Id
private int taskId;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "jobId", updatable=false, insertable=false)
public J job;
public J getJob() {
return job;
}
}
@Entity
@Table("Job")
@SecondaryTable("TechinalJob")
public class TechnicalJob extends Job<TechnicalJob, TechnicalTask> {
//get all relations from parent and additional columns
}
@Entity
@Table("Task")
@SecondaryTable("TechinalTask")
public class TechnicalTask extends Task<TechnicalTask, TechnicalJob> {
//get all relations from parent and additional columns
}
并为 Task 和 TechnicalTask 编写一个通用查询,我打算使用 Criteria。在我的 DAO 中,我会有类似
的东西public class JobDAO <J extends Job> {
protected Class<? extends Job> jobClass = Job.class;
public List<J> getJobs(int id) {
return (List<T>)(entityManager.unwrap(Session.class)).createCriteria(jobClass, "j").list();
}
}
public class TaskDAO <T extends Task> {
public List<T> getTasks
}
public class TechnicalJobDAO extends JobDAO<TechnicalJob> {
@PostConstruct
public void init() {
jobClass = TechnicalJob.class;
}
//get all parents methods
}
public class TechnicalTaskDAO extends TaskDAO<TechnicalTaskk> {
//get all parents methods
}
hibernate 中的隐式多态性是我不去使用 HQL 查询的另一个原因,尽管它们很优雅。现在我正在放弃直接查询 Job 和 Task,但是由于隐式多态性,即使我使用 Hibernate Table 每个子类继承也是行不通的。
谢谢..