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 点的末尾)。

  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 进入 TechnicalJob),例如 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 注意到的那样,异常是由于缺少映射目标而抛出的。

  1. 您有作业及其子类,每个作业都有任务列表,每个子作业都有常规任务列表和另一个专门任务列表,例如 TechnicalTask​​s。您的 Java 代码有点像 Job 有 Taks 而 TechnicalJobs 有 Tasks(继承自 Job)和它自己的 technicalTask​​s 集合。

在那种情况下,它们必须映射到不同的连接 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 每个子类继承也是行不通的。

谢谢..