Будьте в спящем режиме: родительские/Дочерние отношения в единственной таблице

Я едва вижу любой указатель на следующей проблеме, связанной для Спящего режима. Это принадлежит реализации наследования с помощью таблицы единой базы данных с отношениями отцов и детей к себе. Например:

CREATE TABLE Employee (
  empId BIGINT NOT NULL AUTO_INCREMENT,
  empName VARCHAR(100) NOT NULL,
  managerId BIGINT,
  CONSTRAINT pk_employee PRIMARY KEY (empId)
)

Здесь, managerId столбец может быть пустым, или может указать на другую строку Списка сотрудников. Бизнес-правило требует, чтобы Сотрудник знал обо всем своем reportees и чтобы он знал о его менеджере. Бизнес-правила также позволяют строкам иметь пустой указатель managerId (у генерального директора организации нет менеджера).

Как мы отображаемся, эти отношения в В спящем режиме, стандарт many-one отношения не работает здесь? Особенно, если я хочу реализовать свои Объекты не только как соответствующий класс Объекта "Сотрудника", а скорее несколько классов, таких как "менеджер", "Помощник управляющего", "Инженер" и т.д., каждый наследовавшийся от "Сотрудника" супер класс объекта, некоторый объект, имеющий атрибуты, которые на самом деле не относятся ко всем, например, "менеджер" получает Льготы, другие не делают (соответствующий столбец таблицы принял бы пустой указатель, конечно).

Пример кода ценился бы (я намереваюсь использовать, в спящем режиме 3 аннотации).

8
задан Pascal Thivent 9 May 2010 в 13:27
поделиться

3 ответа

Здесь вы выражаете две концепции:

  1. наследование, и вы хотите отобразить свою иерархию наследования в одной таблице.
  2. отношения родитель / ребенок.

Для реализации 1. вам необходимо использовать Hibernate одну таблицу для иерархии классов стратегию:

@Entity
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(
    name="emptype",
    discriminatorType=DiscriminatorType.STRING
)
public abstract class Employee { ... }

@Entity
@DiscriminatorValue("MGR")
public class Manager extends Employee { ... }

Для реализации 2. вам нужно добавить две ассоциации с самореференцией на ] Сотрудник :

  • у многих сотрудников есть ноль или один менеджер (который также является Сотрудником )
  • у одного сотрудника ноль или много репортеров

В результате Сотрудник может выглядеть так:

@Entity
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(
    name="emptype",
    discriminatorType=DiscriminatorType.STRING
)
public abstract class Employee { 

    ... 

    private Employee manager;
    private Set<Employee> reportees = new HashSet<Employee>();

    @ManyToOne(optional = true)
    public Employee getManager() {
        return manager;
    }

    @OneToMany
    public Set<Employee> getReportees() {
        return reportees;
    }

    ...
}

В результате получатся следующие таблицы:

CREATE TABLE EMPLOYEE_EMPLOYEE (
        EMPLOYEE_ID BIGINT NOT NULL,
        REPORTEES_ID BIGINT NOT NULL
    );

CREATE TABLE EMPLOYEE (
        EMPTYPE VARCHAR(31) NOT NULL,
        ID BIGINT NOT NULL,
        NAME VARCHAR(255),
        MANAGER_ID BIGINT
    );

ALTER TABLE EMPLOYEE ADD CONSTRAINT SQL100311183749050 PRIMARY KEY (ID);

ALTER TABLE EMPLOYEE_EMPLOYEE ADD CONSTRAINT SQL100311183356150 PRIMARY KEY (EMPLOYEE_ID, REPORTEES_ID);

ALTER TABLE EMPLOYEE ADD CONSTRAINT FK4AFD4ACE7887BF92 FOREIGN KEY (MANAGER_ID)
    REFERENCES EMPLOYEE (ID);

ALTER TABLE EMPLOYEE_EMPLOYEE ADD CONSTRAINT FKDFD1791F25AA2BE0 FOREIGN KEY (REPORTEES_ID)
    REFERENCES EMPLOYEE (ID);

ALTER TABLE EMPLOYEE_EMPLOYEE ADD CONSTRAINT FKDFD1791F1A4AFCF1 FOREIGN KEY (EMPLOYEE_ID)
    REFERENCES EMPLOYEE (ID);
9
ответ дан 5 December 2019 в 12:57
поделиться

Не уверен, что вы действительно хотите, но я думаю, что вам нужна таблица для иерархии классов

В этом случае каждая сущность сортируется с помощью DISCRIMINATOR_COLUMN следующим образом

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(
    name="EMPLOYEE_TYPE", 
    discriminatorType = DiscriminatorType.STRING
)
@DiscriminatorValue("EMPLOYEE")
public class Employee {

    @Id @GeneratedValue
    @Column(name="EMPLOYEE_ID") 
    private Integer id = null;

}

И его дочерние элементы отображаются в соответствии с

@Entity
@DiscriminatorValue("MANAGER")
public class Manager extends Employee {

    // Manager properties goes here        
     ...
}

. Чтобы проверить, давайте сделаем следующее

SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
Session session = sessionFactory.openSession();

/*
insert 
into
    Employee
    (EMPLOYEE_TYPE) 
values
    ('EMPLOYEE')
*/
session.save(new Employee());

/*
insert 
into
    Employee
    (EMPLOYEE_TYPE) 
values
    ('MANAGER')
*/
session.save(new Manager());

session.clear();
session.close();

Но вместо наследования (которое вы можете увидеть много столбцов NULL из-за того, что несколько сущностей используют одну и ту же таблицу - при использовании InheritanceType.SINGLE_TABLE), ваша модель будет лучше, как показано ниже

@Entity
public class Employee { 

    private Employee manager;
    private List<Employee> reporteeList = new ArrayList<Employee>();

    /**
    * optional=true
    * because of an Employee could not have a Manager
    * CEO, for instance, do not have a Manager
    */  
    @ManyToOne(optional=true)
    public Employee getManager() {
        return manager;
    }

    @OneToMany
    public List<Employee> getReporteeList() {
        return reporteeList;
    }

}

Не стесняйтесь выбирать лучший подход, отвечающий вашим потребностям.

с уважением,

1
ответ дан 5 December 2019 в 12:57
поделиться

Большое спасибо, ребята. Я создал свою сущность «Сотрудник» следующим образом:

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(
    name="EMPLOYEE_TYPE", 
    discriminatorType = DiscriminatorType.STRING
)
@DiscriminatorValue("Employee")
public abstract class Employee {

    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="EMPLOYEE_ID") 
    private Integer empId = null;

    @Column(name="EMPLOYEE_NAME") 
    private String empName = null;

    @Column(name="EMPLOYEE_SECRETARY")
    private String secretary;

    @Column(name="EMPLOYEE_PERKS")
    private int perks;       

    @ManyToOne(targetEntity = Employee.class, optional=true)
@JoinColumn(name="MANAGER_ID", nullable=true)
private Employee manager = null;

    @OneToMany  
    private Set<Employee> reportees = new HashSet<Employee>();

    ...        

    public Set<Employee> getReportees() {
        return reportees;
    } 
}

Затем я добавил другие классы сущности без тела, а только значения столбцов Дискриминатора, такие как Manager, CEO и AsstManager. Я решил позволить Hibernate создать таблицу за меня. Ниже приводится основная программа:

SessionFactory sessionFactory = HibernateUtil.sessionFactory;
Session session = sessionFactory.openSession();
Transaction newTrans = session.beginTransaction();

CEO empCeo = new CEO();
empCeo.setEmpName("Mr CEO");
empCeo.setSecretary("Ms Lily");

Manager empMgr = new Manager();
empMgr.setEmpName("Mr Manager1");
empMgr.setPerks(1000);
empMgr.setManager(empCeo);

Manager empMgr1 = new Manager();
empMgr1.setEmpName("Mr Manager2");
empMgr1.setPerks(2000);
empMgr1.setManager(empCeo);

AsstManager asstMgr = new AsstManager();
asstMgr.setEmpName("Mr Asst Manager");
asstMgr.setManager(empMgr);

session.save(empCeo);
session.save(empMgr);
session.save(empMgr1);
session.save(asstMgr);
newTrans.commit();

System.out.println("Mr Manager1's manager is : "
        + empMgr.getManager().getEmpName());
System.out.println("CEO's manager is : " + empCeo.getManager());
System.out.println("Asst Manager's manager is : " + asstMgr.getManager());
System.out.println("Persons Reporting to CEO: " + empCeo.getReportees());

session.clear();
session.close();

Код работает нормально, Hibernate самостоятельно создавал столбец «MANAGER_EMPLOYEE_ID», в котором хранится FK. Я указал имя JoinColumn, чтобы сделать его «MANAGER_ID». Hibernate также создает таблицу EMPLOYEE_EMPLOYED, однако данные в ней не сохраняются.

Метод getReportees () возвращает значение null, в то время как getManager () работает нормально, как и ожидалось.

3
ответ дан 5 December 2019 в 12:57
поделиться
Другие вопросы по тегам:

Похожие вопросы: