Java [JPA] Liste in andere Tabelle schreiben

ang3l

Ensign
Registriert
Okt. 2006
Beiträge
192
hallo zusammen

ich schreibe gerade eine kleine website für meine filme.
java-mässig habe ich eine klasse film, welche auf eine tabelle in der mysql-db (innodb) verweist/gespeichert wird. nun will ich dies per jpa abspeichern. dies funktioniert, wenn ich die kategorien nicht abspeichere. die kategorien werden im film-objekt als liste von typ enum abgespeichert und sollten in die tabelle "categories" geschrieben werden. diese habe ich in mysql von der film-tabelle per foreign-key auf die film-id der categories-tabelle verlinkt. in der (java) film-klasse habe ich für die verlinkung folgendes deklariert:
Code:
@OneToMany
@JoinColumn(name="film_id")
public List<String> getCategories() {
    return categories;
}

es kommt nun immer eine riesige fehlermeldung, von welche ich jedoch nicht entschlüsseln kann, wo der fehler liegen könnte.
habt ihr mir einen ansatz? was habe ich vergessen/falsch gemacht?

vielen dank!
 
Zuletzt bearbeitet:
es kommt nun immer eine riesige fehlermeldung, von welche ich jedoch nicht entschlüsseln kann, wo der fehler liegen könnte.

Poste doch mal diesen Stacktrace... Mal abgesehen davon, dass man aus dem minimalistischen Code Fragment nicht wirklich was rauslesen kann ;)
 
Zuletzt bearbeitet:
nja viel mehr code sollte ja nicht entstehen wenn man in eine verlinkte tabelle eine liste schreiben will?

fehlermeldung:

Code:
HTTP Status 500 - 

type Exception report

message 

description The server encountered an internal error () that prevented it from fulfilling this request.

exception 
org.apache.jasper.JasperException: Exception [EclipseLink-30005] (Eclipse Persistence Services - 2.3.2.v20111125-r10461): org.eclipse.persistence.exceptions.PersistenceUnitLoadingException
Exception Description: An exception was thrown while searching for persistence archives with ClassLoader: WebappClassLoader
  context: /test
  delegate: false
  repositories:
    /WEB-INF/classes/
----------> Parent Classloader:
org.apache.catalina.loader.StandardClassLoader@4115fa10

Internal Exception: javax.persistence.PersistenceException: Exception [EclipseLink-28018] (Eclipse Persistence Services - 2.3.2.v20111125-r10461): org.eclipse.persistence.exceptions.EntityManagerSetupException
Exception Description: Predeployment of PersistenceUnit [film] failed.
Internal Exception: Exception [EclipseLink-7250] (Eclipse Persistence Services - 2.3.2.v20111125-r10461): org.eclipse.persistence.exceptions.ValidationException
Exception Description: [class film.Film] uses a non-entity [class java.lang.String] as target entity in the relationship attribute [method getCategories].
	org.apache.jasper.servlet.JspServletWrapper.handleJspException(JspServletWrapper.java:549)
	org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:470)
	org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:390)
	org.apache.jasper.servlet.JspServlet.service(JspServlet.java:334)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:722)


root cause 
Exception [EclipseLink-30005] (Eclipse Persistence Services - 2.3.2.v20111125-r10461): org.eclipse.persistence.exceptions.PersistenceUnitLoadingException
Exception Description: An exception was thrown while searching for persistence archives with ClassLoader: WebappClassLoader
  context: /test
  delegate: false
  repositories:
    /WEB-INF/classes/
----------> Parent Classloader:
org.apache.catalina.loader.StandardClassLoader@4115fa10

Internal Exception: javax.persistence.PersistenceException: Exception [EclipseLink-28018] (Eclipse Persistence Services - 2.3.2.v20111125-r10461): org.eclipse.persistence.exceptions.EntityManagerSetupException
Exception Description: Predeployment of PersistenceUnit [film] failed.
Internal Exception: Exception [EclipseLink-7250] (Eclipse Persistence Services - 2.3.2.v20111125-r10461): org.eclipse.persistence.exceptions.ValidationException
Exception Description: [class film.Film] uses a non-entity [class java.lang.String] as target entity in the relationship attribute [method getCategories].
	org.eclipse.persistence.exceptions.PersistenceUnitLoadingException.exceptionSearchingForPersistenceResources(PersistenceUnitLoadingException.java:127)
	org.eclipse.persistence.jpa.PersistenceProvider.createEntityManagerFactory(PersistenceProvider.java:115)
	javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:51)
	javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:33)
	database.DatabaseOperator.<init>(DatabaseOperator.java:28)
	org.apache.jsp.view.jsp.index_jsp._jspService(index_jsp.java:117)
	org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
	org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:432)
	org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:390)
	org.apache.jasper.servlet.JspServlet.service(JspServlet.java:334)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:722)


root cause 
javax.persistence.PersistenceException: Exception [EclipseLink-28018] (Eclipse Persistence Services - 2.3.2.v20111125-r10461): org.eclipse.persistence.exceptions.EntityManagerSetupException
Exception Description: Predeployment of PersistenceUnit [film] failed.
Internal Exception: Exception [EclipseLink-7250] (Eclipse Persistence Services - 2.3.2.v20111125-r10461): org.eclipse.persistence.exceptions.ValidationException
Exception Description: [class film.Film] uses a non-entity [class java.lang.String] as target entity in the relationship attribute [method getCategories].
	org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.predeploy(EntityManagerSetupImpl.java:1402)
	org.eclipse.persistence.internal.jpa.deployment.JPAInitializer.callPredeploy(JPAInitializer.java:98)
	org.eclipse.persistence.jpa.PersistenceProvider.createEntityManagerFactory(PersistenceProvider.java:105)
	javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:51)
	javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:33)
	database.DatabaseOperator.<init>(DatabaseOperator.java:28)
	org.apache.jsp.view.jsp.index_jsp._jspService(index_jsp.java:117)
	org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
	org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:432)
	org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:390)
	org.apache.jasper.servlet.JspServlet.service(JspServlet.java:334)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:722)


root cause 
Exception [EclipseLink-28018] (Eclipse Persistence Services - 2.3.2.v20111125-r10461): org.eclipse.persistence.exceptions.EntityManagerSetupException
Exception Description: Predeployment of PersistenceUnit [film] failed.
Internal Exception: Exception [EclipseLink-7250] (Eclipse Persistence Services - 2.3.2.v20111125-r10461): org.eclipse.persistence.exceptions.ValidationException
Exception Description: [class film.Film] uses a non-entity [class java.lang.String] as target entity in the relationship attribute [method getCategories].
	org.eclipse.persistence.exceptions.EntityManagerSetupException.predeployFailed(EntityManagerSetupException.java:221)
	org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.predeploy(EntityManagerSetupImpl.java:1402)
	org.eclipse.persistence.internal.jpa.deployment.JPAInitializer.callPredeploy(JPAInitializer.java:98)
	org.eclipse.persistence.jpa.PersistenceProvider.createEntityManagerFactory(PersistenceProvider.java:105)
	javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:51)
	javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:33)
	database.DatabaseOperator.<init>(DatabaseOperator.java:28)
	org.apache.jsp.view.jsp.index_jsp._jspService(index_jsp.java:117)
	org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
	org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:432)
	org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:390)
	org.apache.jasper.servlet.JspServlet.service(JspServlet.java:334)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:722)


root cause 
Exception [EclipseLink-7250] (Eclipse Persistence Services - 2.3.2.v20111125-r10461): org.eclipse.persistence.exceptions.ValidationException
Exception Description: [class film.Film] uses a non-entity [class java.lang.String] as target entity in the relationship attribute [method getCategories].
	org.eclipse.persistence.exceptions.ValidationException.nonEntityTargetInRelationship(ValidationException.java:1355)
	org.eclipse.persistence.internal.jpa.metadata.accessors.mappings.RelationshipAccessor.getReferenceDescriptor(RelationshipAccessor.java:508)
	org.eclipse.persistence.internal.jpa.metadata.accessors.mappings.OneToManyAccessor.processUnidirectionalOneToManyTargetForeignKeyRelationship(OneToManyAccessor.java:282)
	org.eclipse.persistence.internal.jpa.metadata.accessors.mappings.OneToManyAccessor.processUnidirectionalOneToManyMapping(OneToManyAccessor.java:253)
	org.eclipse.persistence.internal.jpa.metadata.accessors.mappings.OneToManyAccessor.process(OneToManyAccessor.java:143)
	org.eclipse.persistence.internal.jpa.metadata.MetadataProject.processOwningRelationshipAccessors(MetadataProject.java:1450)
	org.eclipse.persistence.internal.jpa.metadata.MetadataProject.processStage3(MetadataProject.java:1685)
	org.eclipse.persistence.internal.jpa.metadata.MetadataProcessor.processORMMetadata(MetadataProcessor.java:535)
	org.eclipse.persistence.internal.jpa.deployment.PersistenceUnitProcessor.processORMetadata(PersistenceUnitProcessor.java:526)
	org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.predeploy(EntityManagerSetupImpl.java:1337)
	org.eclipse.persistence.internal.jpa.deployment.JPAInitializer.callPredeploy(JPAInitializer.java:98)
	org.eclipse.persistence.jpa.PersistenceProvider.createEntityManagerFactory(PersistenceProvider.java:105)
	javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:51)
	javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:33)
	database.DatabaseOperator.<init>(DatabaseOperator.java:28)
	org.apache.jsp.view.jsp.index_jsp._jspService(index_jsp.java:117)
	org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
	org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:432)
	org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:390)
	org.apache.jasper.servlet.JspServlet.service(JspServlet.java:334)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:722)


note The full stack trace of the root cause is available in the Apache Tomcat/7.0.27 logs.
Apache Tomcat/7.0.27
 
Der springende Punkt in deinem Stacktrace ist imho:

Exception Description: [class film.Film] uses a non-entity [class java.lang.String] as target entity in the relationship attribute [method getCategories].

Du versucht also eine Liste von Strings in einer eigenen Tabelle zu persistieren. Wenn ich mich richtig erinner, dann ist ein String keine erlaubte Entität in einer OneToMany Beziehung, weil es keine ID (in was für einer Form auch immer) hat. (vgl. auch stackoverflow)

Ich würd Dir einfach empfehlen, dass Du eine entsprechende Klasse "Categorie" als Entität aufbaust und gegenüber dieser dann das Mapping durchführst - das sollte dann eigentlich gehen und wäre aus OO sicht wohl besser geeignet.
 
ok ich hab noch etwas gefunden, es müsste wohl eher so heissen:
Code:
@OneToMany
@JoinColumn(name="film_id", referencedColumnName="ID")
public List<String> getCategories() {
	return categories;
}

und deine vorgeschlagene richtung scheint auch richtig zu sein!
jetzt verstehe ich aber etwas nicht.

ich sage ja, dass ich jeweils auf die id's referenzieren will. dann brauch ich nicht weiter ein objekt, was eine ID sein kann, ich beschreibe ja nur die anderen spalten in der tabelle. die id's werden ja automatisch per definition von "@JoinColumn(name="film_id", referencedColumnName="ID")" beschrieben?

und der andere punkt bei deinem vorschlag: die klasse Category existiert bei mir schon, aber als enum. die kann ich ja nicht als entität haben? bzw. ich müsste noch eine id darin haben, auf welche referenziert wird, aber das wäre ja falsch?
 
JoinColumn sagt, dass an Hand von "film_id" und "ID" in deinem Beispiel der Join durchgeführt werden soll. Die ID's werden nicht zu diesem Zeitpunkt geschrieben, sondern zum Zeitpunkt, an dem Du dein Objekt persistierst. Das Du an Hand der Fremdschlüsselbeziehung joinen willst, ist klar.

Ich würde vermutlich die Kategorie irgendwie so in der Art wrappen und damit dann arbeiten:

Code:
import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;

@SuppressWarnings("serial")
@Entity
@Table(name = "Categorie")
public class Categorie implements Serializable {

    public enum CategorieType {
        HORROR, COMEDIAN;
    }

    private long id;

    private CategorieType categorieType;

    private Film film;

    protected Categorie() {

    }

    public Categorie(CategorieType type) {
        setCategorieType(type);
    }

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_STORE")
    @SequenceGenerator(name = "SEQ_STORE", sequenceName = "categorie_seq", initialValue = 1, allocationSize = 1)
    @Column(name = "id", insertable = false, updatable = false)
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    @Column(name = "categorieType", nullable = false, insertable = true, updatable = true)
    @Enumerated(EnumType.STRING)
    public CategorieType getCategorieType() {
        return categorieType;
    }

    public void setCategorieType(CategorieType categorieType) {
        this.categorieType = categorieType;
    }

    @ManyToOne(targetEntity=sample.pack.Film.class)
    @JoinColumn(name = "FILM_ID")
    public Film getFilm() {
        return film;
    }

    public void setFilm(Film film) {
        this.film = film;
    }
}

Code:
    @OneToMany(mappedBy = "film")
    public List<Categorie> getCategories() {
        return categories;
    }


Und dann halt entsprechend den Join durchführen - das sollte so eigentlich in der Art gehen.

Aber was ich jetzt noch nicht ganz verstanden habe: Ein Film kann beliebig viele Kategorien haben, aber eine Kategorie gehört zu genau einem Film?

Für mich hört sich das Ganze ja eher nach einer n:n Beziehung an. Ein Film kann beliebig viele Kategorien haben, einer Kategorie können beliebig viele Filme zugeordnet werden, oder?

\\Edit: Ich sollt schlafen gehen, anstelle unüberlegt irgendwelche komischen Fragen zu stellen ;)
 
Zuletzt bearbeitet:
boah danke vielmals!!

ich schaue dies mal in ruhe an aber es sieht ziemlich genau nach dem aus was ich brauche! besten dank!
 
Zurück
Oben