Search code examples
hibernatejpaormjoinhibernate-onetomany

Hibernate Table per Subclass approach - mappedBy reference an unknown target entity property


I have a table hierarchy like

Job{jobId, title} with One to Many relation with

Task{taskId, jobId(FK), task_title} with One to Many relation with

SubTask{subTaskId, TaskId(FK), subtask_title}.

Now I have a subset of tables which extend these above primary tables like

TechinalJob{jobId(FK), Technical_Details},

TechinalTask{taskId(FK), Technical_Task_Details},

TechinalSubTask{subTaskId(FK), Technical_SubTask_Details}.

Similarly I will have Administrative Jobs/Tasks/SubTasks.

But the catch is I dont have a relation ship between Techincal Jobs/Tasks/SubTasks or Administrative ones.. The relationship is through original Job/Task/SubTask. I dont have primary keys in Techincal Jobs/Tasks/SubTasks or Administrative ones either. So If I have to create a bidirectional one-to-many relationship between TechinalJob and TechincalTask I have to go through the Job/Task/SubTask table structure do the following. How can I achieve this using Hibernate inheritance.

Update 03/25/2015:

After trying ver2 suggested by Zielu. This is the revised code

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

}

When I tried this I got an exception saying Caused by: org.hibernate.AnnotationException: mappedBy reference an unknown target entity property: TechinalTask.job in TechincalJob.tasks. It is not able to find job in TechnicalTask though I am extending Task and making sure job in Task is public.

Thanks in advance..


Solution

  • Thanks Zielu, I appreciate all your effort in helping me out.. I finally found a solution. But it is not through hibernate inheritance.. I used combination of SecondaryTable and java inheritance. The way I did it is by making superclass @MappedSuperClass and making the child object use the parent's table as @Table and child's table as @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
    
    }
    

    And to write a common query for both Task and TechnicalTask I am planning to use Criteria. In my DAO I will have something like

    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
    }
    

    Implicit polymorphism in hibernate was another reason why I did not go for HQL queries despite their elegance. Now I am loosing on querying directly on Job and Task, but that would have not worked even if I went with Hibernate Table per subclass inheritance because of implicit polymorphism.

    Thanks..