# JPA Entitys anlegen OneToMany Relation abbilden



## slay24 (16. Mai 2009)

Hallo erstmal,
Ich habe folgendes Problem:
Ich möchte in EJB 3.0 mit JPA 2 Tabellen abbilden die eine 1:n Beziehung besititzen.
Es handelt sich um die Tabellen Buchung und Kunde. Hierbei hat eine Buchung einen Kunden und ein Kunde n Buchungen.

Das hier ist mein Versuch, aber ich komme nicht so recht weiter.
Vielen dank für eure Hilfe.

Buchung1

```
package persistence;
import java.util.List;
import java.io.Serializable;

import javax.persistence.*;

@Entity
@Table(name="Buchung1")
public class Buchung implements Serializable{
	
	private static final long serialVersionUID = 1L;
	private int Buchungsnummer;
	private boolean bezahlt;
	private Kunde kunde;
	
	
    @ManyToOne
    @JoinColumn(name="KundenID", nullable=false)
    public Kunde getKunde() 
    {
    	return kunde;
    }
	
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	public int getBuchungsnummer() {
		return Buchungsnummer;
	}
	public void setBuchungsnummer(int buchungsnummer) {
		Buchungsnummer = buchungsnummer;
	}
	
	
	public boolean isBezahlt() {
		return bezahlt;
	}
	public void setBezahlt(boolean bezahlt) {
		this.bezahlt = bezahlt;
	}
	
	
	
}
```

Kunde

```
@Entity
@Table(name="Kunde")
public class Kunde implements Serializable{
	
	private int KundenID, PLZ, BLZ;	
	
//Geändert-----

	@OneToMany(mappedBy="Buchungen",targetEntity=Buchung.class, fetch=FetchType.EAGER)
	private Collection orders;

// --------
	
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	public int getKundenID() {
		return KundenID;
	}
	public void setKundenID(int kundenID) {
		KundenID = kundenID;
	}
	public int getPLZ() {
		return PLZ;
	}
	public void setPLZ(int plz) {
		PLZ = plz;
	}
	public int getBLZ() {
		return BLZ;
	}
	public void setBLZ(int blz) {
		BLZ = blz;
	}
	
}
```


----------



## MarcB (17. Mai 2009)

Also da kann ich jetzt auf die schnelle keine Fehler erkennen.
Die Getter und Setter für die orders fehlen halt.

Würde die Annotations immer auf die Felder machen, auf den Methoden finde ich das sehr unübersichtlich. Ist letztendlich aber Geschmackssache. Mischformen sind aber böse.

Was gibts denn genau für ein Problem?

Wenn es die Tabellen schon gibt, kann man mit den gängigen IDEs die Entity-Klassen generieren lassen, das ist dann zwar nicht immer ganz korrekt (CascadeType, TemporalType, usw.), verhindert aber nervige Tippfehler in den Feldnamen.

PS: equals und hashCode fehlen noch.


----------



## slay24 (17. Mai 2009)

Also ich versteh leider garnich wie die setter und getter methoden für die orders aussehn soll. Und wie kann man sich den die Entitys generieren lassen, ich verwende Eclipse und kann die Funktionalität nicht finden?

(die momentane Fehlermeldung ist das mein EAR Projekt not bound ist. Der Fehler verschwindet wenn ich die OnetoMAny und ManyToOne einträge lösche)


----------



## MarcB (17. Mai 2009)

Naja, wie Getter und Setter nun mal aussehen: Sie geben halt die Collection zurück.
Achso die Collection sollte doch Objekte vom Typ Buchung aufnehmen!? Dann würde man das so abbilden:

```
...
@OneToMany(mappedBy="kunde", fetch=FetchType.EAGER)
private Collection<Buchung> orders;
public Collection<Buchung> getOrders(){
return orders;
}
public void setOrders(Collection<Buchung> orders){
this.orders = orders;
}
...
```

Warum eigentlich "orders" und nicht "buchungen"? Und wozu hat der Kunde noch eine Buchung (die nicht OneToOne gemappt wird)?

Die Fehlermeldung könnte bedeuten, dass in der IDE kein Application Server ausgewählt wurde, der eine entsprechende JPA-Implementierung enthält.
Kann mich aber irren, denn ich kenne die Meldung nicht.

Wie man Entity-Klassen mit eclipse generiert steht da:
Generating entities from tables
Mit Netbeans kann man in jedem Projekt einfach durch (Rechtsklick auf Projekt) "New->Other...->Persistence->Entity Classes from Database" einen Wizard dafür öffnen.

Mit IDEA und JDeveloper gehts auch, die haben auch eine ausführliche Hilfefunktion in der das beschrieben wird.


----------



## slay24 (17. Mai 2009)

Ich weiß was setter und getter sind ^^ also ganz so newbie bin ich nicht. Das Problem ist auch nicht die Logik an sich. Aber ich versteh nicht ganz was die OneToMany Beziehung beim Kunden macht und ich finde einfach nirgentwo eine vollständige implementierung einer solchen Beziehung die ich mir zum vorbild nehmen könnte.

P.S.: danke das du dir soviel Zeit nimmst!


----------



## MarcB (17. Mai 2009)

slay24 hat gesagt.:


> P.S.: danke das du dir soviel Zeit nimmst!



Hehe, war grad Grillen.
Dafür kriegst du jetzt aber auch ein komplettes Beispiel.

Klasse Kunde:

```
package de.firma.projekt.entities;

import java.io.Serializable;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;

@Entity
public class Kunde implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;
    private int plz;
    private int blz;
    @OneToMany(mappedBy = "kunde", cascade = CascadeType.ALL)
    private List<Buchung> buchungen;

    public int getBlz() {
        return blz;
    }

    public void setBlz(int blz) {
        this.blz = blz;
    }

    public List<Buchung> getBuchungen() {
        return buchungen;
    }

    public void setBuchungen(List<Buchung> buchungen) {
        this.buchungen = buchungen;
    }

    public int getId() {
        return id;
    }

    protected void setId(int id) {
        this.id = id;
    }

    public int getPlz() {
        return plz;
    }

    public void setPlz(int plz) {
        this.plz = plz;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Kunde other = (Kunde) obj;
        if (this.id != other.id) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 97 * hash + this.id;
        return hash;
    }
}
```

Klasse Buchung:

```
package de.firma.projekt.entities;

import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

@Entity
@Table(name = "Buchung1")
public class Buchung implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int buchungsnummer;
    private boolean bezahlt;
    @ManyToOne
    private Kunde kunde;

    public boolean isBezahlt() {
        return bezahlt;
    }

    public void setBezahlt(boolean bezahlt) {
        this.bezahlt = bezahlt;
    }

    public int getBuchungsnummer() {
        return buchungsnummer;
    }

    protected void setBuchungsnummer(int buchungsnummer) {
        this.buchungsnummer = buchungsnummer;
    }

    public Kunde getKunde() {
        return kunde;
    }

    public void setKunde(Kunde kunde) {
        this.kunde = kunde;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Buchung other = (Buchung) obj;
        if (this.buchungsnummer != other.buchungsnummer) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        int hash = 3;
        hash = 19 * hash + this.buchungsnummer;
        return hash;
    }
}
```

Die persistence.xml:
[XML]<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
  <persistence-unit name="SpassProjektPU" transaction-type="RESOURCE_LOCAL">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <class>de.firma.projekt.entities.Buchung</class>
    <class>de.firma.projekt.entities.Kunde</class>
    <properties>
      <property name="hibernate.connection.username" value="user"/>
      <property name="hibernate.connection.driver_class" value="org.apache.derby.jdbc.ClientDriver"/>
      <property name="hibernate.connection.password" value="password"/>
      <property name="hibernate.connection.url" value="jdbc:derby://localhost:1527/testdb"/>
      <property name="hibernate.cache.provider_class" value="org.hibernate.cache.NoCacheProvider"/>
      <property name="hibernate.dialect" value="org.hibernate.dialect.DerbyDialect"/>
      <property name="hibernate.hbm2ddl.auto" value="update"/>
    </properties>
  </persistence-unit>
</persistence>[/XML]

Und was zum Testen des Ganzen (einfach ein paar mal laufen lassen):

```
package de.firma.projekt.run;

import de.firma.projekt.entities.Buchung;
import de.firma.projekt.entities.Kunde;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import javax.persistence.Query;

public class Testlauf {

    public static void main(String[] args) {
        //PU bauen
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("SpassProjektPU");
        //Manager & Transaction holen
        EntityManager manager = emf.createEntityManager();
        EntityTransaction transaction = manager.getTransaction();
        //Transaction starten
        transaction.begin();
        //Neuen Kunden anlegen
        Kunde kunde = new Kunde();
        kunde.setBlz(1234);
        kunde.setPlz(5678);
        //Zwei Buchungen für den Kunden anlegen
        Buchung buchung1 = new Buchung();
        buchung1.setKunde(kunde);
        buchung1.setBezahlt(false);
        Buchung buchung2 = new Buchung();
        buchung2.setKunde(kunde);
        buchung2.setBezahlt(true);
        //Mit Kunde "verdrahten"
        List<Buchung> buchungen = new ArrayList<Buchung>();
        buchungen.add(buchung1);
        buchungen.add(buchung2);
        kunde.setBuchungen(buchungen);
        //Persistieren (Nur den Kunden, der Rest wird kaskadiert
        manager.persist(kunde);
        //Commit
        transaction.commit();
        //Die Kunden mal ausgeben
        printKundenBuchungen(manager);
        //Manager zu machen
        manager.close();
    //fertig;
    }

    public static void printKundenBuchungen(EntityManager em) {
        Query q = em.createQuery("select object(o) from Kunde as o");
        List<Kunde> kunden = q.getResultList();
        System.out.println("Gebe Kunden aus...");
        for (Kunde kunde : kunden) {
            System.out.println("Kunde: " + kunde.getId());
            System.out.println("Buchungen:");
            List<Buchung> buchungen = kunde.getBuchungen();
            for (Buchung buchung : buchungen) {
                System.out.println("-" + buchung.getBuchungsnummer());
            }
        }

    }
}
```

Habe die JavaDB (Derby) benutzt. Parameter stehen in der persistence.xml.
Als JPA Implementierung Hibernate, wenn du was anderes verwenden willst und nicht weisst was du brauchst, sag Bescheid.

Annotiert ist nur minimal, also keine Constraints oder andere Tabellennamen.


----------



## slay24 (18. Mai 2009)

Danke hab mit hilfe von eclipse auch endlich funktioniernde Entities generiert. Nur fehlen mir restriktionen. Ich möchte z.B. verhindern das ein Fremdschlüssel nicht Null sein darf bzw in der Herkunftstabelle vorhanden sein muss. 
Beispiel: Ich möchte Buchungen verhindern die keinen gültigen Kunden enthalten.


----------



## MarcB (18. Mai 2009)

So einfache Restriktionen kann man mit der Column-Annotation abbilden.

In dem Fall wärs dann einfach:

```
@Column(nullable=false)
private Kunde kunde;
```


----------



## slay24 (18. Mai 2009)

hm ja das entspricht ja lediglich einem not null. aber wie kann ich den Abbilden das er immer gegenprüft ob der FK auch als PK in der anderen Tabelle vorhanden ist


----------



## MarcB (18. Mai 2009)

Das hast du doch implizit durch die Beziehungen ManyToOne und OneToMany festgelegt.

Wenn Beziehungen nicht optional sein sollen, kann man das einfach so machen:

```
@ManyToOne(optional=false)
private Kunde kunde;
```


----------



## slay24 (18. Mai 2009)

cool danke


----------

