2010-03-11 6 views
8

Ich sehe kaum einen Zeiger auf das folgende Problem im Zusammenhang mit Hibernate. Dies bezieht sich auf das Implementieren der Vererbung unter Verwendung einer einzelnen Datenbanktabelle mit einer Eltern-Kind- -Beziehung zu sich selbst. Zum Beispiel:Hibernate: Parent/Child-Beziehung in einer einzelnen Tabelle

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

Hier wird die MANAGERID Säule kann null sein oder kann auf eine andere Zeile der Mitarbeiter Tabelle verweisen. Die Geschäftsregel setzt voraus, dass der Mitarbeiter über alle seine Mitarbeiter informiert ist und dass er über seinen/ihren Vorgesetzten Bescheid weiß. Die Geschäftsregeln ermöglichen auch Zeilen mit null managerId (der CEO der Organisation hat keinen Manager).

Wie können wir diese Beziehung in Hibernate abbilden, funktioniert die Standard-Viele-zu-Eins-Beziehung hier nicht? Vor allem, wenn ich meine Entitäten nicht nur als entsprechende Entity-Klasse "Employee" implementieren möchte, sondern mehrere Klassen wie "Manager", "Assistant Manager", "Engineer" usw., die jeweils von der Entity-Klasse "Employee" erben eine Entität mit Attributen, die nicht wirklich für alle gelten, zum Beispiel "Manager" erhält Perks, andere nicht (die entsprechende Tabellenspalte würde natürlich null akzeptieren).

Beispiel Code würde geschätzt werden (ich beabsichtige Hibernate 3 Anmerkungen).

+0

Dupe: http://stackoverflow.com/questions/1862457/hibernate3-self-referencing-objects – hobodave

+0

@hobodave: Ich hätte gerne ein Codebeispiel, das Annotationen (auf Hibernate 3) verwendet, das ist die Absicht. Würdest du zustimmen? – dchucks

Antwort

9

Sie äußern sich hier zwei Konzepte:

  1. Erbe und Sie möchten Ihre Vererbungshierarchie in einer einzigen Tabelle abzubilden.
  2. eine Eltern/Kind-Beziehung.

    @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 implementieren:

1. Zur Umsetzung werden Sie single table per class hierarchy Strategie Hibernate verwenden müssen., Müssen Sie zwei sich selbst verweisende Assoziationen auf Employee hinzuzufügen:

  • viele Mitarbeiter haben null oder ein Manager hat null oder viele
  • ein Mitarbeiter reportee (die auch eine Employee ist) (s)

Das resultierende Employee Mai sieht wie folgt aus:

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

    ... 
} 

Und dies in den folgenden Tabellen führen würde:

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); 
+0

Ich bin verwirrt Pascal, wenn seine Single Table Inheritance brauche ich eine Join Tabelle Employee_Employee? – dchucks

+0

Wie kann ich auch die Spalte MANAGER_ID zuordnen? – dchucks

+0

@Dee Hmm ... Was? :) Ich bekomme die erste Frage nicht. Employee_Employee ist für die OneToMany-Selbstreferenzierungszuordnung. Ist es das was du meinst? –

1

Ich bin nicht sicher über Sie wirklich wollen, aber ich glaube, Sie wollen eine Tabelle pro Klassenhierarchie

In diesem Fall wird jede Entität durch eine DISCRIMINATOR_COLUMN sortiert als

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

} 
folgt

Und seine Kinder ist nach

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

    // Manager properties goes here   
    ... 
} 

um t abgebildet o Test, lassen Sie uns gehen Sie wie folgt

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(); 

Aber statt der Vererbung (die Sie viele NULL-Spalte sehen kann durch mehr als eine Entity den gleichen Tisch zu teilen - wenn InheritanceType.SINGLE_TABLE Strategie), Ihr Modell wäre besser als folgt

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

} 

Fühlen Sie sich frei zur Wahl der beste Ansatz, die Ihre Bedürfnisse erfüllen.

Grüßen,

3

Danke eine Tonne Jungs. Ich habe meine Mitarbeiter Entity wie folgt:

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

ich dann andere Entity Klassen ohne Körper hinzugefügt, aber Diskriminatorfilter Spalten Werte, gerade wie Geschäftsführer, CEO und AsstManager. Ich entschied mich, Hibernate den Tisch für mich erstellen zu lassen. Es folgt das Hauptprogramm:

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(); 

Der Code fein läuft, Hibernate wurde eine Spalte „MANAGER_EMPLOYEE_ID“ auf seinem eigenen zu schaffen, wo sie die FK speichern. Ich habe den JoinColumn-Namen angegeben, um ihn zu "MANAGER_ID" zu machen. Hibernate erstellt auch eine Tabelle EMPLOYEE_EMPLOYED, die Daten werden jedoch dort nicht gespeichert.

Die Methode getReportees() gibt eine Null zurück, getManager() funktioniert wie erwartet.

Verwandte Themen