Frage

Ich sehe kaum einen Zeiger auf das folgende Problem im Zusammenhang mit Hibernate. Dies bezieht sich auf Vererbung Implementierung einer einzelnen Datenbanktabelle mit einer Eltern-Kind mit Verhältnis zu sich selbst. Zum Beispiel:

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

Hier ist die MANAGERID Spalte null sein kann oder zu einer anderen Zeile der Mitarbeiter Tabelle zeigen. Geschäftsregel erfordert die Mitarbeiter über alle seine reportees kennen und ihn über seine / ihre Manager zu kennen. Die Geschäftsregeln auch Reihen erlauben haben null MANAGERID (Geschäftsführer der Organisation keinen Manager).

Wie ordnen wir diese Beziehung in Hibernate, Standard-viele-zu-eins-Beziehung hier nicht funktioniert? Vor allem, wenn ich meine Entitäten implementieren will nicht nur als entsprechende „Mitarbeiter“ Entity-Klasse, sondern mehrere Klassen wie „Manager“, „Assistant Manager“, „Ingenieur“ usw., die jeweils abgeleitet von „Employee“ Super Entitätsklasse , einige Unternehmen Attributen, die eigentlich nicht für alle, zum Beispiel „Manager“ anwenden wird Perks, andere nicht (die entsprechende Tabellenspalte null natürlich annehmen würde).

Beispiel-Code erkannt werden würde (Ich beabsichtige, Hibernate 3 Anmerkungen zu verwenden).

War es hilfreich?

Lösung

Sie sind exprimierenden zwei Konzepte hier:

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

1. Zur Umsetzung werden Sie Hibernate verwenden müssen, einzelne Tabelle pro Klassenhierarchie Strategie:

@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. Zur Umsetzung müssen Sie zwei sich selbst verweisende Assoziationen auf Employee hinzuzufügen:

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

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

Andere Tipps

Dank einer 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 habe dann andere Entity Klassen ohne Körper, sondern nur Werte Diskriminatorfilter Spalten, wie Geschäftsführer, CEO und AsstManager. Ich wählte Hibernate schaffen für mich den Tisch 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 läuft gut, Hibernate wurde eine Spalte „MANAGER_EMPLOYEE_ID“ auf seinem eigenen zu schaffen, wo sie die FK speichern. Ich angegebene JoinColumn Namen „MANAGER_ID“ zu machen. Hibernate schafft auch eine Tabelle EMPLOYEE_EMPLOYED, jedoch werden die Daten dort nicht werden beibehalten.

Methode getReportees () Methode gibt einen Null, während getManager () funktioniert gut, wie erwartet.

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

In diesem Fall jede Entität durch eine DISCRIMINATOR_COLUMN sortiert ist wie folgt

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

}

Und seine Kinder abgebildet nach

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

    // Manager properties goes here        
     ...
}

Um zu testen, lassen Sie uns folgendes tun

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 durch mehr als eine Entität der gleiche Tabelle sehen teilen - wenn InheritanceType.SINGLE_TABLE Strategie), Ihr Modell besser wäre, wie 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 zu Wahl der beste Ansatz, die Ihren Bedürfnissen entsprechen.

Grüße,

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top