# Db4o speichert verschachtelte Objekte nicht vollständig



## canogretic (7. Sep 2012)

Hi, ich bin neu hier im Forum und relativ neu was das entwickeln von Java Anwendungen angeht. Ok ein paar Programme welche keine Grafische Oberfläche enthalten habe ich dann doch schon programmiert.

Derzeit bin ich dabei eine kleine Anwendung zu programmieren mit grafischer Oberfläche, um auch in dem Bereich etwas Erfahrung zu sammeln. Bei der Anwendung geht es um ein Programm welches vielleicht in Zukunft mein Studium unterstützen kann.
Das ganze soll mit der Objektorientierten Datenbank db4o realisiert werden.

Zum Inhalt:
In der Anwendung gibt es ein Datenbankobjekt welches eine TreeMap mit Lehrveranstaltungen beinhaltet. Diese Lehrveranstaltungen haben wiederum TreeMap`s welche die Lerndokumente wie z.B. Skript oder Klausuren enthält. Zu jedem Lerndokument gibt es dann noch Ausarbeitungen wie z.B. Ergaenzungen oder selbst verfasste Texte zu einer Beispielklausur. Diese Ausarbeitungen werden ebenfalls in einer TreeMap gespeichert. 

Das ganze stellt sich also ungefähr so grafisch dar:

DB
   -> Lehrveranstaltungen
                                  -> Lerndokumente
                                                           ->Ausarbeitungen

Mein Problem besteht jetzt darin, dass die Lehrveranstaltungen und Lerndokumente zwar in der Datenbank gespeichert werden und auch ausgelesen werden, aber die Ausarbeitungen fehlen nach jedem Neustart des Programms wieder. Wenn ich während der Laufzeit die Daten eintrage und Anzeigen lasse funktioniert das einwandfrei nur nach einem Neustart des Programms sind die Ausarbeitungen weg.

Vielleicht könnte mir jemand einen Tipp geben was genau ich falsch mache. Ich denke das hängt mit der Abspeicherung des Daten in die DB4o Datenbank zusammen. Daher habe ich meine Datenbank Klasse beigefügt. Das Tutorial der DB4o Datenbank habe ich bereits gelesen. Zumindest den wichtigen Teil mit den storing Objects. Wenn ich das richtig verstanden habe sollten eigentlich alle Daten abgespeichert sein wenn ich das jeweilige Lehrveranstaltungsobjekt in der Datenbank speichere.  
Irgendwie stehe ich gerade auf dem Schlauch.   



```
package storage;

import java.util.List;

import storage.Datenbank;
import storage.Lehrveranstaltung;
import storage.Lerndokument;
import com.db4o.Db4oEmbedded;
import com.db4o.ObjectSet;
import com.db4o.config.EmbeddedConfiguration;
import com.db4o.ext.DatabaseFileLockedException;
import com.db4o.ObjectContainer;
import com.db4o.reflect.jdk.JdkReflector;
import main.Lernmaschine;

public class Datenbank_db4o extends Datenbank {
private static final String dateiname = "lernmaschine.db4o";
private ObjectContainer db;

/**
 * Konstruktor Aufruf der Oberklasse
 */
public Datenbank_db4o() {
	super();
}

/**
 * oeffnet die Datenbank
 */
public void oeffneDB() {
	EmbeddedConfiguration config = Db4oEmbedded.newConfiguration();
	
	config.common().reflectWith(new JdkReflector(Thread.currentThread().getContextClassLoader()));
	
	config.common().updateDepth(8);
	
	db = Db4oEmbedded.openFile(config, dateiname);
}

/**
 * Liest beim start die Daten aus der Datenbank
 */
public void leseDatenEin() throws Exception {
	try {
		System.out.println("Lokaler Betrieb mit eingebetteter DB " + dateiname);
		
		oeffneDB();
		
		List<Lehrveranstaltung> lvliste = db.query(Lehrveranstaltung.class);
		
		System.out.println(lvliste.size() + "Lehrveranstaltungen eingelesen ...");
		
		for(Lehrveranstaltung lv : lvliste) {
			lehrveranstaltungen.put(lv.gibName(), lv);
		}
	}
	finally {
		db.close();
	}
}

/**
 * Legt eine Lehrveranstaltung an und speichert diese 
 * in der Datenbank
 * 
 * @return die eingetragene Lehrveranstaltung
 */
public Lehrveranstaltung lehrveranstaltungAnlegen(Lehrveranstaltung lv) {
		Lehrveranstaltung lvx = lehrveranstaltungen.put(lv.gibName(), lv);
		speichereLehrveranstaltung(lv);
		return lvx;
}


/**
 * Legt ein Lerndokument an und speichert dieses in
 * der Datenbank
 * 
 * @return das eingetragene Lerndokument
 */
@Override
public Lerndokument lerndokumentAnlegen(Lehrveranstaltung lv, Lerndokument ld) {
    Lehrveranstaltung lvGelesen = leseLehrveranstaltung(lv);
    Lerndokument ldresult = super.lerndokumentAnlegen(lv, ld);
    if (lvGelesen != null) {
        super.lerndokumentAnlegen(lvGelesen, ld);
        speichereLehrveranstaltung(lvGelesen);
    }
    else {
        System.out.println("Die Lehrveranstaltung " + lv.gibName() + 
                " konnte nicht aus der Datenbank gelesen werden!");
    }
    return ldresult;

}

/**
 * Legt eine Ausarbeitung an und speichert die
 * Aenderung in der Datenbank
 *
 * @return        die eingetrage Ausarbeitung oder 
 *                die Ausarbeitung, die in der DB
 *                ueberschrieben wurde.
 */
@Override
public Lerndokument ausarbeitungenAnlegen(Lehrveranstaltung lv, Lerndokument ld, Lerndokument ausa) {
	
    Lehrveranstaltung lvGelesen = leseLehrveranstaltung(lv);
    Lerndokument ldresult = super.ausarbeitungenAnlegen(lv, ld, ausa);
    if (lvGelesen != null) {
        System.out.println(lvGelesen.gibLerndokument(ld.gibName()));
        super.ausarbeitungenAnlegen(lvGelesen, lvGelesen.gibLerndokument(ld.gibName()), ausa);
        speichereLehrveranstaltung(lvGelesen);
    }
    else {
        System.out.println("Die Lehrveranstaltung " + lv.gibName() + 
                " konnte nicht aus der Datenbank gelesen werden!");
    }
    return ldresult;
}

/** 
 * Methode zum Auslesen einer Lehrveranstaltung
 * aus der Datenbank
 * 
 * @return  das gelesene Lehrveranstaltung-Objekt
 *
 **/
public Lehrveranstaltung leseLehrveranstaltung(Lehrveranstaltung lv) {   

    Lehrveranstaltung lvGelesen = null; //super.gibLehrveranstaltung(lv.gibName());
    lvGelesen = super.gibLehrveranstaltung(lv.gibName());
    return lvGelesen;		
}

/** 
 * Methode zum Abspeichern einer Lehrveranstaltung in
 * der Objektdatenbank. Die DB wird danach geschlossen.
 * 
 * @return  true, wenn die Daten gespeichert werden konnten
 *
 **/
  public boolean speichereLehrveranstaltung(Lehrveranstaltung lv) {   
    
    try {
    	oeffneDB();
    	db.store(lv);
    }
    finally {
    	db.close();
    }
    return true;
  }
}
```


----------



## pl4gu33 (7. Sep 2012)

also eigentl. sollten alle Werte gespeichert werden ... ich hab deine Struktur auch nochmal nachgebaut also 3 Objekte ineinander und mit deinen Config- Einstellungen wird es auch ohne Probleme gespeichert. Soweit ich weiß konnte man store() auch nicht wirklich behindern, dass er nicht den ganzen Baum speichert. Kann mich aber auch gerade irren, is schon etwas her  

du erweiterst ja die Klasse Datenbank ... was hast du denn darin stehen?

ansonsten poste einfach mal alle Klassen, dann schau ich mir das nochmal an


----------



## canogretic (7. Sep 2012)

Erstmal vielen Dank für den Hinweis.  
Die drei anderen Klassen sehen wie folgt aus:


Oberklasse Datenbank


```
package storage;
import java.util.Map;
import java.util.TreeMap;
import java.util.ArrayList;

public abstract class Datenbank
{
  
  protected TreeMap<String, Lehrveranstaltung> lehrveranstaltungen;
     
  public Datenbank() {
  lehrveranstaltungen = new TreeMap<String, Lehrveranstaltung>();
  }
   
  public abstract void leseDatenEin() throws Exception;
  
  public Lerndokument lerndokumentAnlegen(Lehrveranstaltung lv, Lerndokument ld) {
	  return lv.lerndokumentHinzufuegen(ld);
  }
  
  public Lehrveranstaltung lehrveranstaltungAnlegen(Lehrveranstaltung lv) {
	  return lehrveranstaltungen.put(lv.gibName(), lv);  
  }
  
  public Lerndokument ausarbeitungenAnlegen(Lehrveranstaltung lv, Lerndokument ld, Lerndokument ausa) {
	  return ld.ausarbeitungHinzufuegen(ausa);
  }
  
  public boolean istLehrveranstaltungVorhanden(String name) {
    return lehrveranstaltungen.containsKey(name);
  }
    
  public int gibAnzahlLehrveranstaltungen(){
    return lehrveranstaltungen.size();
  }
    
  public TreeMap<String, Lehrveranstaltung> gibLehrveranstaltungen() {
	  return lehrveranstaltungen;
  }
   
   public Lehrveranstaltung gibLehrveranstaltung(String name) {
	   return lehrveranstaltungen.get(name);
   }
}
```

Klasse der Lehrveranstaltungen


```
package storage;
import java.util.Map;
import java.util.TreeMap;
import java.util.ArrayList;


public class Lehrveranstaltung implements java.io.Serializable
{
    private String name;
    private TreeMap<String, Lerndokument> lerndokument;

    public Lehrveranstaltung(String name)
    {
        this.name = name;
        lerndokument = new TreeMap<String, Lerndokument>();
    }

    public String gibName() {
        return name;
    }
    
    public Lerndokument gibLerndokument(String name) {
    	return lerndokument.get(name);
    }
    
    public TreeMap<String, Lerndokument> gibLerndokumente() {
       return lerndokument;
      }
    
    
    public Lerndokument lerndokumentHinzufuegen(Lerndokument le)
    {
        assert le != null;
    	return lerndokument.put(le.gibName(), le);
    }
    
    public Lerndokument lerndokumentLoeschen(String name) {
    	return lerndokument.remove(name);
    }
    
    public boolean istLerndokumentVorhanden(String name) {
    	return lerndokument.containsKey(name);
    }
    
    public int gibAnzahlLerndokumente() {
    	return lerndokument.size();
    }
}
```

Klasse der Lerndokumente


```
package storage;

import java.util.Map;
import java.util.TreeMap;

public class Lerndokument implements java.io.Serializable
{
	private String name;
    private TreeMap<String, Lerndokument> ausarbeitungen;
    private String speicherort;
    private Kategorie kategorie;
    private Format format;
       
    public Lerndokument(String name, String ort, Format form, Kategorie kat)
    {
        this.name = name;
        kategorie = kat;
        format = form;
        speicherort = ort;
        ausarbeitungen = new TreeMap<String, Lerndokument>();
    }

    public String gibName() 
    {
        return name;
    }
    
    public Kategorie gibKategorie() {
        return kategorie;
    }
        
    public String gibSpeicherort() {
        return speicherort;
    }
    
    public Format gibFormat() {
        return format;
    }
    
    public Lerndokument gibAusarbeitung(String name) {
    	return ausarbeitungen.get(name);
    }
    
    public TreeMap<String, Lerndokument> gibAusarbeitungen() {
    	return ausarbeitungen;
    }
    
    public Lerndokument ausarbeitungLoeschen(Lerndokument ld) {
    	return ausarbeitungen.remove(ld.gibName());
    }
    
    public Lerndokument ausarbeitungHinzufuegen(Lerndokument ausa) {
    	if (ausa.kategorie != Kategorie.AUSARBEITUNG)
            throw new IllegalArgumentException(
            "Fehler beim Eintragen einer Ausarbeitung: " +
            "Das uebergebene Lerndokument ist keine Ausarbeitung!");
            
        if (this.gibKategorie() == Kategorie.AUSARBEITUNG)
            throw new IllegalArgumentException(
            "Fehler! - Bei einer Ausarbeitung kann keine " +
            "Ausarbeitung eingetragen werden!");
            
        return ausarbeitungen.put(ausa.gibName(), ausa);
    }
    
    public int gibAnzahlAusarbeitungen() {
    	return ausarbeitungen.size();
    }
    
    public boolean istAusarbeitungVorhanden(String name) {
    	return ausarbeitungen.containsKey(name);
    }
    
}
```

Es kann vielleicht auch sein das ich beim Aufruf aus dem Menü das ganze evtl falsch angehe.

Hierzu mal ein Auszug aus der Methode die aufgerufen wird beim eintragen der Ausarbeitung:


```
public void ausarbeitungEintragen() {
      Lehrveranstaltung lv = lehrveranstaltungAuswaehlen();
      if (lv == null) return;
      Lerndokument le = lerndokumentAuswaehlen(lv);
      if (le == null) return;
      Format format = formatAuswaehlen();
      if (format == null) return;
      String name = fragen("Name der Ausarbeitung");
      if (name == null) return;
      String ort = fragen("Speicherort der Ausarbeitung");
      if (ort == null) return;
      Lerndokument ausa = new Lerndokument(name, ort, format, Kategorie.AUSARBEITUNG);
    	  if (le.ausarbeitungHinzufuegen(ausa) /*db.ausarbeitungenAnlegen(lv, le, ausa)*/ == null) {
    	  System.out.println();
    	  System.out.println("Die Ausarbeitung " +name+ " zum Lerndokument " + le + " wurden ueberschrieben.");
    	  System.out.println();
      }
      else {
            System.out.println("Die Ausarbeitung " + name + " zum Lerndokument " + le + "wurden eingetragen.");
      }
        return; 
}
```

Bei dem auskommentierten in der Methode bin ich mir nicht ganz sicher was ich verwenden sollte, aber das dürfte so wie ich das sehe das selbe bewirken. Jedenfalls ändert beides nichts bei der Ausführung.


----------



## canogretic (7. Sep 2012)

Ok ich habe das Auskommentierte aus der Methode mal genommen und dann ging es doch und die Sachen wurden abgespeichert und gelesen. Jetzt müsste ich nur noch wissen wieso das so passiert. ICh vermute wenn ich die Ausarbeitung mit Hilfe der Methode der Klasse Lerndokumente eintrage wird der Datenbankeintrag nicht wirklich aktualisiert bzw. nie wirklich abgespeichert, da es dort keinen Eintrag zur Speicherung der DAten gibt. Dort wird nur das Objekt zur TreeMap hinzugefügt und das war es dann. Wenn ich die Methode aus der Datenbank Klasse nehme wird das ganze aktualisiert und richtig gespeichert.


----------



## pl4gu33 (7. Sep 2012)

ich würde erstmal den Code etwas umbauen, dann kannst du auch leichter die Fehler finden 
ich denke mal, dass du wohl, wie du schon sagst, nur auf der Liste arbeitest und bei der anderen Methode speicherst du ja auch


----------



## canogretic (7. Sep 2012)

In wie weit würdest du das ganze umbauen?


----------



## pl4gu33 (7. Sep 2012)

als Beispiele:

returns bei void- Methoden als "abbruch"... Parameter, die nicht genutzt werden in Methoden... irgendwie springst du über mehrere Klassen hin und her zumindest sieht das so aus... Methodennamen machen nicht das, was sie sagen... was soll das mit der Datenbank Klasse und der Vererbung, irgendwie erschließt sich der Sinn mir da nicht, weil du kannst daraus auch einfach 2 Klassen bauen,... sodass du eine eigene Klasse für die Datenbankzugriffe hast, ... sowas alles


----------



## canogretic (7. Sep 2012)

Also das mit der Vererbung bei der Datenbank habe ich drin da es noch andere Klassen gibt. Bevor ich das mit db4o getestet habe, habe ich die Sachen in einer Datei gespeichert. Ich hatte da jetzt auch wieder das ein oder andere geändert zu der Ursprungsversion. Daher sieht das im Augenblick alles vielleicht ein wenig wüst aus, aber ich bin ja auch noch lange nicht fertig. 

Aber erst einmal vielen Dank hast mir echt geholfen.


----------



## pl4gu33 (8. Sep 2012)

damals hat mir das Tutorial sehr geholfen, kannst dir ja mal anschauen

http://community.versant.com/Documentation/Reference/db4o-8.0/java/tutorial/

da werden dann auch später Depth's erklärt, dass du nicht immer den ganzen Baum etc. updatest


----------

