2013-06-20 3 views
2

У нас есть 2 таблицы (активная таблица и таблица архивов), которые имеют одинаковую структуру (например, Employee и EmployeeArchive). Чтобы иметь возможность использовать общий код для использования результатов для обеих таблиц, мы имеем абстрактный родительский класс, который определяет все методы и аннотации. Нам нравится иметь возможность выполнять запросы, которые будут использовать один и тот же запрос для обеих таблиц, и объединить результаты вместе.JPA 2.0/Hibernate InheritanceType TABLE_PER_CLASS и OneToMany/ManyToOne двунаправленное отношение

У нас есть еще одна сущность/таблица (например, Organization.) С onetomany/manytoone двунаправленной связи с Employee; Organization имеет ListEmployee s и каждый сотрудник имеет организацию. При получении сотрудниками организации через ассоциацию мы хотим, чтобы сотрудники из активной таблицы не являлись архивом.

Есть ли способ достичь того, что мы пытаемся или обеспечить жизнеспособное обходное решение?

Мы попытались использовать различные варианты @MappedSuperclass, @Entity/@InheritanceType.TABLE_PER_CLASS, чтобы попытаться достичь того, чего хотим. Каждая реализация почти достигла бы того, чего мы хотим, но не полностью. Например, чтобы иметь возможность запрашивать обе таблицы, мы могли бы иметь абстрактный родительский Entity с InheritanceType.TABLE_PER_CLASS, но тогда у нас не могло быть отношения mappedBy к Employee в 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

У меня подобная проблема. Вы готовы помочь мне с этим? Вот ссылка: http://stackoverflow.com/questions/25252541/generatedvalue-for-a-java-abstract-superclass-over-mysql – CodeMed

ответ

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.

Затем вы можете использовать сопоставление таблицы non-join, которое у вас уже есть, и использовать аннотацию @Where, чтобы ограничить сотрудников в организации теми, у которых IS_ACTIVE установлено значение true. Пример такого подхода is here.

+0

Ваше решение намного более разумно! Мне нравится +1 –

+0

Спасибо sharakan, совместимое отображение похоже, что оно будет работать (еще не пробовал). Стратегия базы данных немного вышла из-под контроля, но у меня будет несколько дискуссий, чтобы узнать, можем ли мы использовать другую стратегию «мягкого удаления», например, просто иметь флаг архива или помещать все данные в таблицу архивов/db, чтобы нам не нужно беспокоиться о том, чтобы запросить оба. – bdrx

1

Это одна из самых раздражающих вещей о Hibernate. Способ сделать это, чтобы иметь еще один абстрактный класс, AbstractMapped, который просто выглядит следующим образом:

@MappedSuperclass 
public abstract class AbstractMapped { 

} 

и тогда AbstractEmployee продлить AbstractMapped. Тогда у вас есть AbstractEmployee как Entity и Mapped Superclass, хотя оба тега являются взаимоисключающими.

+0

Я должен был упомянуть в сообщении, что мы уже пытались это сделать безрезультатно. Мы получаем исключение, инициализирующее блок персистентности. Я уточню вопрос. – bdrx

0

AbstractEmployee должен быть @MappedSuperClass и не должен быть @Entity, который создает таблицу для класса.

Организация должна содержать List<AbstractEmployee> не сотрудника.

+0

Если организация содержит «Список », тогда поиск отношений будет запрашивать обе таблицы, архив и активную, чего мы пытаемся избежать. Мы не хотим, чтобы запрос позволял сотрудникам организации запрашивать таблицу архива. – bdrx