# JPA / EclipseLink: @EmbeddedId und @Id



## XPlayer (10. Jan 2013)

Hallo zusammen,

ich arbeite zurzeit mit JPA / Eclipse Link zum direkten Speichern von Objekten in einer Derby-Datenbank. Nun stehe ich vor einem Problem, an dem ich selbst nicht mehr weiterkomme.

Zunächst einmal die relevanten JPA-Klassen (unnötiger Code wurde entfernt):


```
@Embeddable
public class FileId {

protected FileId() {
}

protected File fileName;

public FileId(File fileName) {
  this.fileName = fileName;
}

// Getter und Setter

// diese ID-Klasse soll später um weitere Attribute zur Identifizierung erweitert werden

}

@MappedSuperClass
public abstract class SuperClass {

@EmbeddedId
private FileId fileId;

protected SuperClass() {
}

public SuperClass(FileId fileId) {
 this.fileId = fileId;
}

// Getter und Setter

}

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public MyClassA extends SuperClass {

@Id
protected String id;

protected MyClassA() {
}

public MyClassA(String id, FileId fileId) {
super(fileId);
this.id = id;
}

// Getter und Setter

}

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public MyClassB extends SuperClass {

protected MyClassB() {
}

public MyClassA(FileId fileId) {
super(fileId);
}

// Getter und Setter

}
```

Bei der Ausführung wird folgende Exception geworfen:


```
...
Exception Description: Entity class [class org.example.MyClassA] has both an @EmbdeddedId (on attribute [fileId]) and an @Id (on attribute [id]. Both ID types cannot be specified on the same entity.
...
```

Folglich ist also das Problem, dass der Primary Key von MyClassA sowohl aus einer @EmbeddedId (alle Attribute der Klasse FileId) als auch einer @Id (Attribut id) besteht, was anscheinend (für mich nicht nachvollziehbar) nicht erlaubt ist.

Wer hat eine Idee, wie ich dieses Problem lösen könnte.

Danke im Voraus!

Gruß
XPlayer


----------



## nillehammer (10. Jan 2013)

> Folglich ist also das Problem, dass der Primary Key von MyClassA sowohl aus einer @EmbeddedId (alle Attribute der Klasse FileId) als auch einer @Id (Attribut id) besteht, was anscheinend (für mich nicht nachvollziehbar) nicht erlaubt ist.


Wenn man sich die Erfordernisse einer DB anschaut, ist das sehr wohl nachvollziehbar. Bei der Definition einer Tabelle musst du Dich für die Spalten entscheiden, die zum Primary Key dazu gehören sollen. Hier kannst du auch nicht sagen: "Ich hätte gerne einerseits einen numerischen und andererseits auch noch eine Kombination von Spalten".

Die mögliche Lösung hängt davon ab, was du genau mit der EmbeddedId machen willst. Wenn es zunächst nur um die Zusicherung der Eindeutigkeit geht, könntest Du über die betroffenen Felder einen Unique Constraint setzen.


----------



## XPlayer (10. Jan 2013)

Hi,



> Hier kannst du auch nicht sagen: "Ich hätte gerne einerseits einen numerischen und andererseits auch noch eine Kombination von Spalten".



Man hätte es doch intern einfach so implementieren können, das das ID-Attribut und die Attribute der ID-Klasse zusammen genommen werden und diese dann als Primary Key der entsprechenden Klasse definiert werden, oder? 



> Die mögliche Lösung hängt davon ab, was du genau mit der EmbeddedId machen willst. Wenn es zunächst nur um die Zusicherung der Eindeutigkeit geht, könntest Du über die betroffenen Felder einen Unique Constraint setzen.



Ein Objekt der Klasse MyClassA soll durch fileId und id eindeutig bestimmt werden können, ein Objekt von MyClassB dagegen soll nur durch fileId eindeutig bestimmt werden.

Es sollen also in der Tabelle MyClassA z.B. folgende Entitäten möglich sein:


```
fileId | id
1      | 1
1      | 2
```

In der Tabelle MyClassB dagegen darf folgendes nicht möglich sein (Primary Key {fileId} verletzt):


```
fileId
1      
1
```

Gruß
XPlayer


----------



## nillehammer (11. Jan 2013)

> Ein Objekt der Klasse MyClassA soll durch fileId und id eindeutig bestimmt werden können, ein Objekt von MyClassB dagegen soll nur durch fileId eindeutig bestimmt werden.


Und durch die Verrbugsbeziehung  zur Klasse SuperClass kommen die sich ins Gehege. Da gibt's eine Lösung. Stelle Dein Mapping von Fields auf die getter um (JPA-Annotationen auf die getter). Das ist auch (zumindest in der Hibernate-Doku) die Empfehlung. Methoden haben im Gegensatz zu Feldern nämlich den Vorteil, überschrien werden zu können. Damit kannst Du auch das Mapping in den Unterklassen neu definieren.


----------

