JPA: Entity Klasse @JoinColumns Problem

Gongo82

Neues Mitglied
Hallo Leute,

ich verwende Netbeans 7.4 auf meinen Mac und arbeite zur Zeit an einer Webanwendung.

In Netbeans hab ich mir die Entity Klassen von meiner existierenden DB generieren lassen.

Wenn ich die Anwendung laufen lasse wird die folgende Exception geworfen.

The @JoinColumns on the annotated element [field tblSeminarCollection] from the entity class [class entities.TblDozent] is incomplete. When the source entity class uses a composite primary key, a @JoinColumn must be specified for each join column using the @JoinColumns. Both the name and the referencedColumnName elements must be specified in each such @JoinColumn.

Ich suche schon seit Tagen nach einer Lösung und kann nichts finden das mir weiter helfen könnte, vielleicht weiss von euch jemand, was das Problem ist und kann mir einen Tip geben...wäre super!

Hier die genaue Exception:

Java:
Schwerwiegend:   Exception while invoking class org.glassfish.persistence.jpa.JPADeployer prepare method
Schwerwiegend:   javax.persistence.PersistenceException: Exception [EclipseLink-28018] (Eclipse Persistence Services - 2.5.0.v20130507-3faac2b): org.eclipse.persistence.exceptions.EntityManagerSetupException
Exception Description: Predeployment of PersistenceUnit [jdbcNOK_PU] failed.
Internal Exception: Exception [EclipseLink-7220] (Eclipse Persistence Services - 2.5.0.v20130507-3faac2b): org.eclipse.persistence.exceptions.ValidationException
Exception Description: The @JoinColumns on the annotated element [field tblSeminarCollection] from the entity class [class entities.TblDozent] is incomplete. When the source entity class uses a composite primary key, a @JoinColumn must be specified for each join column using the @JoinColumns. Both the name and the referencedColumnName elements must be specified in each such @JoinColumn.
	at org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.createPredeployFailedPersistenceException(EntityManagerSetupImpl.java:1950)
	at org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.predeploy(EntityManagerSetupImpl.java:1941)
	at org.eclipse.persistence.jpa.PersistenceProvider.createContainerEntityManagerFactory(PersistenceProvider.java:322)
	at org.glassfish.persistence.jpa.PersistenceUnitLoader.loadPU(PersistenceUnitLoader.java:199)
	at org.glassfish.persistence.jpa.PersistenceUnitLoader.<init>(PersistenceUnitLoader.java:107)
	at org.glassfish.persistence.jpa.JPADeployer$1.visitPUD(JPADeployer.java:223)
	at org.glassfish.persistence.jpa.JPADeployer$PersistenceUnitDescriptorIterator.iteratePUDs(JPADeployer.java:510)
	at org.glassfish.persistence.jpa.JPADeployer.createEMFs(JPADeployer.java:230)
	at org.glassfish.persistence.jpa.JPADeployer.prepare(JPADeployer.java:168)
	at com.sun.enterprise.v3.server.ApplicationLifecycle.prepareModule(ApplicationLifecycle.java:922)
	at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:431)
	at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:219)
	at org.glassfish.deployment.admin.DeployCommand.execute(DeployCommand.java:491)
	at com.sun.enterprise.v3.admin.CommandRunnerImpl$2$1.run(CommandRunnerImpl.java:527)
	at com.sun.enterprise.v3.admin.CommandRunnerImpl$2$1.run(CommandRunnerImpl.java:523)

Es geht um die nun folgenden Tabellen:

Java:
package entities;

import java.io.Serializable;
import java.util.Collection;
import javax.persistence.Column;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import javax.validation.constraints.Size;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;


@Entity
@Table(name = "tbl_Dozent")
@XmlRootElement
@NamedQueries({
    @NamedQuery(name = "TblDozent.findAll", query = "SELECT t FROM TblDozent t"),
    @NamedQuery(name = "TblDozent.findByDozId", query = "SELECT t FROM TblDozent t WHERE t.tblDozentPK.dozId = :dozId"),
    @NamedQuery(name = "TblDozent.findByDozName", query = "SELECT t FROM TblDozent t WHERE t.dozName = :dozName"),
    @NamedQuery(name = "TblDozent.findByDozNachname", query = "SELECT t FROM TblDozent t WHERE t.dozNachname = :dozNachname"),
    @NamedQuery(name = "TblDozent.findByDozTel", query = "SELECT t FROM TblDozent t WHERE t.dozTel = :dozTel"),
    @NamedQuery(name = "TblDozent.findByTblLoginUsersLoginEmail", query = "SELECT t FROM TblDozent t WHERE t.tblDozentPK.tblLoginUsersLoginEmail = :tblLoginUsersLoginEmail")})
public class TblDozent implements Serializable {

    private static final long serialVersionUID = 1L;
    @EmbeddedId
    protected TblDozentPK tblDozentPK;
    @Size(max = 45)
    @Column(name = "doz_name")
    private String dozName;
    @Size(max = 45)
    @Column(name = "doz_nachname")
    private String dozNachname;
    @Size(max = 45)
    @Column(name = "doz_tel")
    private String dozTel;
    @JoinTable(name = "tbl_Dozent_has_tbl_seminar", joinColumns = {
        @JoinColumn(name = "tbl_Dozent_doz_id", referencedColumnName = "doz_id")}, inverseJoinColumns = {
        @JoinColumn(name = "tbl_seminar_sem_id", referencedColumnName = "sem_id")})
    @ManyToMany
    private Collection<TblSeminar> tblSeminarCollection;
    @JoinColumn(name = "tbl_login_users_login_email", referencedColumnName = "login_email", insertable = false, updatable = false)
    @ManyToOne(optional = false)
    private TblLoginUsers tblLoginUsers;

    public TblDozent() {
    }

    public TblDozent(TblDozentPK tblDozentPK) {
        this.tblDozentPK = tblDozentPK;
    }

    public TblDozent(int dozId, String tblLoginUsersLoginEmail) {
        this.tblDozentPK = new TblDozentPK(dozId, tblLoginUsersLoginEmail);
    }

    public TblDozentPK getTblDozentPK() {
        return tblDozentPK;
    }

    public void setTblDozentPK(TblDozentPK tblDozentPK) {
        this.tblDozentPK = tblDozentPK;
    }

    public String getDozName() {
        return dozName;
    }

    public void setDozName(String dozName) {
        this.dozName = dozName;
    }

    public String getDozNachname() {
        return dozNachname;
    }

    public void setDozNachname(String dozNachname) {
        this.dozNachname = dozNachname;
    }

    public String getDozTel() {
        return dozTel;
    }

    public void setDozTel(String dozTel) {
        this.dozTel = dozTel;
    }

    @XmlTransient
    public Collection<TblSeminar> getTblSeminarCollection() {
        return tblSeminarCollection;
    }

    public void setTblSeminarCollection(Collection<TblSeminar> tblSeminarCollection) {
        this.tblSeminarCollection = tblSeminarCollection;
    }

    public TblLoginUsers getTblLoginUsers() {
        return tblLoginUsers;
    }

    public void setTblLoginUsers(TblLoginUsers tblLoginUsers) {
        this.tblLoginUsers = tblLoginUsers;
    }

    @Override
    public int hashCode() {
        int hash = 0;
        hash += (tblDozentPK != null ? tblDozentPK.hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object object) {
        // TODO: Warning - this method won't work in the case the id fields are not set
        if (!(object instanceof TblDozent)) {
            return false;
        }
        TblDozent other = (TblDozent) object;
        if ((this.tblDozentPK == null && other.tblDozentPK != null) || (this.tblDozentPK != null && !this.tblDozentPK.equals(other.tblDozentPK))) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return "entities.TblDozent[ tblDozentPK=" + tblDozentPK + " ]";
    }

}

Java:
package entities;

import java.io.Serializable;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Embeddable;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;


@Embeddable
public class TblDozentPK implements Serializable {
    @Basic(optional = false)
    @Column(name = "doz_id")
    private int dozId;
    @Basic(optional = false)
    @NotNull
    @Size(min = 1, max = 255)
    @Column(name = "tbl_login_users_login_email")
    private String tblLoginUsersLoginEmail;

    public TblDozentPK() {
    }

    public TblDozentPK(int dozId, String tblLoginUsersLoginEmail) {
        this.dozId = dozId;
        this.tblLoginUsersLoginEmail = tblLoginUsersLoginEmail;
    }

    public int getDozId() {
        return dozId;
    }

    public void setDozId(int dozId) {
        this.dozId = dozId;
    }

    public String getTblLoginUsersLoginEmail() {
        return tblLoginUsersLoginEmail;
    }

    public void setTblLoginUsersLoginEmail(String tblLoginUsersLoginEmail) {
        this.tblLoginUsersLoginEmail = tblLoginUsersLoginEmail;
    }

    @Override
    public int hashCode() {
        int hash = 0;
        hash += (int) dozId;
        hash += (tblLoginUsersLoginEmail != null ? tblLoginUsersLoginEmail.hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object object) {
        // TODO: Warning - this method won't work in the case the id fields are not set
        if (!(object instanceof TblDozentPK)) {
            return false;
        }
        TblDozentPK other = (TblDozentPK) object;
        if (this.dozId != other.dozId) {
            return false;
        }
        if ((this.tblLoginUsersLoginEmail == null && other.tblLoginUsersLoginEmail != null) || (this.tblLoginUsersLoginEmail != null && !this.tblLoginUsersLoginEmail.equals(other.tblLoginUsersLoginEmail))) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return "entities.TblDozentPK[ dozId=" + dozId + ", tblLoginUsersLoginEmail=" + tblLoginUsersLoginEmail + " ]";
    }
    
}
 

stg

Top Contributor
Dein Primärschlüssel besteht aus der Dozent-ID und der Email-Adresse. Fürs mapping zwischen Dozent und Seminar verwendest du aber nur die Dozent-ID. Es sollte sich selbst erklären, dass das so nicht funktionieren kann.

Ein solches Mapping mit zusammengesetzten Schlüsseln habe ich ehrlich gesagt noch nie gemacht. Bei mir haben alle Tabellen immer eine eigene (technische) ID als PK. Wenn ich darauf angewiesen bin, dass wie in deinem Beispiel die Kombination aus DozentID und Email eindeutig sein soll, dann setz ich einfach zusätzlich zu der extra technischen ID noch ein UniqueConstraint auf die entsprechenden Spalten. Das erspart einem beim Mapping definitiv einiges an Kopfzerbrechen, weil man alles auf dem Standardweg lösen kann.
 

Spitfire777

Bekanntes Mitglied
Hi!

Ich würde es auch mit nur einer ID lösen und den Rest auf Unique setzen. Allerdings hat man dann immer ein ungewünschtes Beziehungsobjekt und das kann bei hochskalierten Anwendungen unter Umständen auch die Performance drücken (ich gehe mal davon aus).

Hab mit EclipseLink keine Erfahrung und weiß auch nicht gegen welche JPA-Version du implementierst.

Hier aber ein Beispiel aus meinem J2EE-Vorlesungsskript mit Hibernate:

Java:
@Entity
public class Bestellung {
    ...
    @Id
    private Long id;
    ...

    @ManyToMany
    @JoinTable(name = "bestellung_zu_lieferung",
        joinColumns = @JoinColumn(name = "bestellung_fk"),
        inverseJoinColumns = @JoinColumn(name = "lieferung_fk"))
    private List<lieferungen> lieferungen;

    ...
}

Java:
@Entity
public class Lieferung {
    ...
    @Id
    private Long id;
    ...

    @ManyToMany
    @JoinTable(name = "bestellung_zu_lieferung",
        joinColumns = @JoinColumn(name = "bestellung_fk"),
        inverseJoinColumns = @JoinColumn(name = "lieferung_fk"))
    private List<Bestellung> bestellungen;

    ...
}
 
Zuletzt bearbeitet:
Ähnliche Java Themen
  Titel Forum Antworten Datum
OnDemand Vorgehen DB /Entity Data Tier 2
A Entity Manager Data Tier 4
erdmann Entity-Services ein Antipattern? Data Tier 3
S JPA Cascade: Entity nur speichern, wenn sie nicht schon existiert Data Tier 0
E JPA Session.delete einer Entity wird nicht ausgeführt Data Tier 2
G EJB NoSuchEJBException Zugriff auf Entity Data Tier 6
S [JPA-Neuling] - JPA 2 und dynamische Entity-Typen/DB-Schemata Data Tier 11
Landei JPA - Entity mit Maps Data Tier 2
H [Hibernate] Unknown Entity Data Tier 3
G JPA/ Eclipselink: (Alte) Kopie einer Entity? Data Tier 6
J Servlet mit eigenem Entity-Manager innerhalb von Seam-Projekt Data Tier 3
lumo Hibernate - entity class not found Data Tier 5
J synchronisierte Zugriffe auf die gleiche Entity (JPA) Data Tier 19
LCS Entity mit variablen Tabellennamen Data Tier 3
D jpq entity life cycle - insert, update... Data Tier 5
A @org.hibernate.annotations.Entity(dynamicUpdate=true, optimisticLock=OptimisticLockType.ALL) Data Tier 2
T [JPA] Update Entity in Entity Data Tier 2
byte Hibernate: Criteria & SubQuery - Unknown Entity null Data Tier 1
Final_Striker EJB3: Entity nach persist wiederfinden Data Tier 8
N Entity-Object muss auf Client aktualisiert werden Data Tier 13
0 org.hibernate.MappingException: Unknown entity Data Tier 8
K Hibernate: Unknown entity Data Tier 7
S JPA Name der konkreten Klasse Data Tier 5
F Hibernate HQL INSERT in Tabelle mit eingebetteter Klasse Data Tier 4
neonfly <exclude-unlisted-classes>true</exclude-unlisted-classes> mag <class>package.Klasse</class> nicht Data Tier 2
H Zusammengesetzte mehrere Klasse als eine Tabelle Data Tier 6

Ähnliche Java Themen


Oben