# JPA und Tabellenstruktur



## Guest (28. Sep 2008)

Hallo,

es gibt eine Klasse Person, dort stehen die grunddaten einer Person wie name, geschlecht etc.. Dann soll es Klassen wie Kunde odr Mitarbeiter geben, die halt die eigenschaften der Klasse Person beinhalten. In derDatenbank sol dies so abgebildet werden, dass für jede Klasse eine Tabelle angelegt wird und der PrimaryKey der Tabellen für Mitarbeiter Kunden etc. der PrimaryKey von Personen ist. Also eine OneToOne Beziehung. Dies stellt sich jedoch als ziemlich schwierig heraus. Denn durch vererbung wird eine Tabelle Person mit einer DiscriminatorColumn erzeugt und wenn ich eine Person erzeuge die gleichzeitig Kunde und Mitarbeiter ist, werden zwei Datensätze in der Tabelle für Personen eingetragen. Zweite Möglichkeit ist mit @SecondaryTable alle s in die Klasse Person zu Packen und wie gewollt in Tabellen zu verteilen. Nachteil ist eine riesen Klasse Person. Kann man es auf mehrere Kalssen verteilen und die gewollte Tabellenstruktur erzeugen?


----------



## Guest (28. Sep 2008)

Mach aus der Klasse Person "MappedSuperclass"
	
	
	
	





```
@MappedSuperclass
public abstract class Person
{
   @Id
   @GeneratedValue
   private Long id;

   ...
}

@Entity
@Table(name = "MITARBEITER")
public class Mitarbeiter extends Person
{
   ...
}

@Entity
@Table(name = "KUNDE")
public class Kunde extends Person
{
   ...
}
```
Wenn du jetzt über Person Queries absetzts (z.B. SELECT p FROM Person p), werden beide Tabellen gelesen. 
Bei Mitarbeiter und Kunde jeweils nur die eine Tabelle.


----------



## Guest (29. Sep 2008)

Danke. Aber hierbei ensteht das Problem, dass in alle Unterklassentabellen die Eigenschaften von Personen übernommen werden und die Tabelle Person nicht erstellt wird. Somit steht in Kunde und Mitarbeiter jewals der Vor und Nachname etc.


----------



## Guest (29. Sep 2008)

OK, habe verstanden, wie du es meinst. Hmm...
Wie wäre es mit Komposition?
	
	
	
	





```
@Entity
public class Person
{
   ...
}

@MappedSuperclass
public abstract class PersonComposite
{
   @Id
   @GeneratedValue
   private Long id;

   @ManyToOne(optional = false, cascade = { CascadeType.PERSIST, CascadeType.MERGE })
   @JoinColumn(name = "PERSON_ID", unique = true, updatable = false)
   private Person person;

   ...
}

@Entity
public class Mitarbeiter extends PersonComposite
{
   ...
}

@Entity
public class Kunde extends PersonComposite
{
   ...
}
```
Damit kannst du immer noch alle selektieren (über PersonComposite)
und die Person-Daten sind einmalig in Tabelle Person.

Gruß,
semi


----------



## semi (29. Sep 2008)

Kleine Ergänzung. So sieht es besser aus.
	
	
	
	





```
@Entity
public class PersonData
{
   @Id
   @GeneratedValue
   private Long id;

   ... alle gemeinsamen Daten hierher

   @OneToMany(mappedBy = "personData")
   private Set<Person> personSet = new HashSet<Person>();

   ...
}

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "PTYPE", discriminatorType = DiscriminatorType.STRING, length = 2)
public abstract class Person
{
   @Id
   @GeneratedValue
   private Long id;

   @ManyToOne(optional = false, cascade = { CascadeType.PERSIST, CascadeType.MERGE })
   @JoinColumn(name = "PERSONDATA_ID", unique = true, updatable = false)
   private PersonData personData;

   ...
}

@Entity
@DiscriminatorValue("MA")
public class Mitarbeiter extends Person
{
   ...
}

@Entity
@DiscriminatorValue("KD")
public class Kunde extends Person
{
   ...
}
```


----------



## Guest (30. Sep 2008)

Vielen Dank!!!

Die ersion mit der kleinen Ergänzug klappt einwandfrei. Nur wird da keine Discriminator Spalte in der Tabelle eingefügt. Nicht das es mich stören würde. Denn so sollte es auch sein. Nur wofür wird die Angegeben oder wo befindet die sich. Ist eine reine Verständnisfrage.


----------



## semi (30. Sep 2008)

Anonymous hat gesagt.:
			
		

> Vielen Dank!!!
> 
> Die ersion mit der kleinen Ergänzug klappt einwandfrei. Nur wird da keine Discriminator Spalte in der Tabelle eingefügt. Nicht das es mich stören würde. Denn so sollte es auch sein. Nur wofür wird die Angegeben oder wo befindet die sich. Ist eine reine Verständnisfrage.


Ups, sorry, das wird da gar nicht benötigt (gilt nur für SINGLE_TABLE). Dafür ist das "unique" bei personData hinderlich, 
da keine zwei Datensätze (Mitarbeiter und Kunde) auf gleiche Persondaten verweisen können.
Hier eine korrigierte Version
	
	
	
	





```
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class Person
{
   @Id
   @GeneratedValue
   private Long id;

   @ManyToOne(optional = false, cascade = { CascadeType.PERSIST, CascadeType.MERGE })
   @JoinColumn(updatable = false)
   private PersonData personData;
   ...
}

@Entity
public class Mitarbeiter extends Person
{
   @Column(nullable = false, unique = true)
   private String personalnummer; // Besser wäre Embeddable mit Zusatzfunktionen für Personalnummer
   ...
}

@Entity
public class Kunde extends Person
{
   @Column(nullable = false, unique = true) 
   private String kundennummer; // Besser wäre Embeddable mit Zusatzfunktionen für Kundennummer
   ...
}
```
Jetzt ist es zwar möglich mehrere Kunden/Mitarbeiter mit gleichen Persondaten zu verlinken, das dürfte aber das geringere Übel sein. Das kannst du durch die Programmlogik verhindern.

Das ganze ist nicht für tiefe Strukturen geeignet, da dabei zu viele Joins im Spiel sind.
Sowas wird z.B. aus "SELECT p FROM Person p".
Sieht übel aus, was?  :lol:
	
	
	
	





```
select
  person0_.id as id157_,
  person0_.personData_id as personData2_157_,
  person0_1_.personalnummer as personal2_158_,
  person0_2_.kundennummer as kundennu2_167_,
  case 
   when person0_1_.id is not null then 1  // Die Zahlen verwendet die JPA Implementierung zur Laufzeit, um die Daten
   when person0_2_.id is not null then 2  // den jeweiligen Klassen (Kunde/Mitarbeiter) zuordnen zu können.
   when person0_.id is not null then 0    // Dieser Fall ist nur theoretisch, da eine der beiden Bedingungen oben immer
                                          // zutrifft. Die Klasse Person ist ja abstrakt, daher nicht direkt instanzierbar.
  end as clazz_ 
 from
  Person person0_ 
 left outer join
  Mitarbeiter person0_1_ 
   on person0_.id=person0_1_.id 
 left outer join
  Kunde person0_2_ 
   on person0_.id=person0_2_.id
```


----------



## Kris (15. Okt 2008)

Würde es dann mehr Sinn machen auf die Vererbeung zu verzichten?

public void Kunde implements Serializable{

  @Id
  private long id;

  @ManyToOne(nullable=false .....)
  private Person person;

  @Column
  private int kundennummer;
}


----------

