Hibernate Benutzerdatenbank logischer Ansatz

Schau mal hier


Java:
import junit.framework.TestCase;

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.tool.hbm2ddl.SchemaExport;

import de.tutorials.hibernate.model.User;

public class TestKlasse extends TestCase {

	private User user = new User();

	private User chef = new User();

	private SessionFactory sessionFactory;

	long idUser, idChef;

	protected void setUp() throws Exception {
		super.setUp();

		Configuration configuration = new Configuration().configure();
		configuration.setProperty("hibernate.show_sql", "true");
		SchemaExport export = new SchemaExport(configuration);
		export.create(false, true);
		sessionFactory = configuration.buildSessionFactory();

		Session session = null;
		Transaction transaction = null;
		try {
			session = sessionFactory.openSession();
			transaction = session.beginTransaction();
			
			chef.setNachname("Boss");
			chef.setVorname("Der");
			
			session.save(chef);
			
			user.setNachname("Müller");
			user.setVorname("Michael");
			
			session.save(user);
			
			chef.add(user);

			session.update(chef);

			user.setVorgesetzter(chef);

			session.update(user);
			
			transaction.commit();
		} catch (HibernateException e) {
			if (transaction != null) {
				transaction.rollback();
				throw e;
			}
		} finally {
			if (session != null) {
				session.close();
			}
		}
		idUser = user.getId();
		idChef = chef.getId();
	}

	public void testLoad() {
		Session session = null;
		try {
			session = sessionFactory.openSession();
			User user = (User) session.load(User.class, idUser);
			User chef = (User) session.load(User.class, idChef);

			assertEquals("Müller", user.getNachname());
			assertEquals("Michael", user.getVorname());
			
			User vorg = user.getVorgesetzter();
			
			assertEquals(this.chef.getVorname(), vorg.getVorname());
			assertEquals(this.chef.getNachname(), vorg.getNachname());
			assertEquals(this.chef.getId(), vorg.getId());

			

			assertEquals("Boss", chef.getNachname());
			assertEquals("Der", chef.getVorname());
			
			User unterg = chef.getUntergebene().get(0);
			
			assertEquals(this.user.getNachname(), unterg.getNachname());
			assertEquals(this.user.getVorname(), unterg.getVorname());
			assertEquals(this.user.getId(), unterg.getId());
			
		

		} finally {
			if (session != null && session.isConnected()) {
				session.close();
			}
		}
	}

}

Java:
package de.tutorials.hibernate.model;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

public class User implements Serializable{
	
	private static final long serialVersionUID = 8608688581595289547L;
	private long id;
	private String vorname = null;
	private String nachname = null;
	
	private User vorgesetzter = null;
	private List<User> untergebene = new ArrayList<User>();
	
	
	public String getNachname() {
		return nachname;
	}
	public void setNachname(String nachname) {
		this.nachname = nachname;
	}
	public List<User> getUntergebene() {
		return untergebene;
	}
	public void setUntergebene(List<User> untergebene) {
		this.untergebene = untergebene;
	}
	public User getVorgesetzter() {
		return vorgesetzter;
	}
	public void setVorgesetzter(User vorgesetzter) {
		this.vorgesetzter = vorgesetzter;
	}
	public String getVorname() {
		return vorname;
	}
	public void setVorname(String vorname) {
		this.vorname = vorname;
	}
	public long getId() {
		return id;
	}
	@SuppressWarnings("unused")
	private void setId(long id) {
		this.id = id;
	}
	public boolean add(User o) {
		return untergebene.add(o);
	}
	public boolean remove(User o) {
		return untergebene.remove(o);
	}
}

XML:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
  "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
  "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">


<hibernate-mapping package="de.tutorials.hibernate.model">
	<class name="User">
		<id name="id">
			<generator class="native" />
		</id>
		<property name="nachname" />
		<property name="vorname" />

		<many-to-one name="vorgesetzter" column="boss" />

		<bag name="untergebene" inverse="true">
			<key column="boss" />
			<one-to-many class="User" />
		</bag>
	</class>
</hibernate-mapping>

MFG

zEriX
 
Zuletzt bearbeitet von einem Moderator:
erstmal ein großes danke für dein tutorial!
ist soweit nun auch alles klar geworden und hilft mir sehr gut meine letzte frage genau zu formulieren

du schreibst bei der objekt-erstellung von chef & user:
Code:
chef.add(user);
...
user.setVorgesetzter(chef);

also wird der user dem chef als untergebener zugewiesen
und
der chef als vorgesetzer für den user gesetzt.

kann dieses doppelt setzen irgendwie vermieten werden, sprich: kann ich nicht lediglich user.setVorgesetzer(chef) auf basis der users ausführen und die
abfrage untergebenen von einem chef irgendwie über hibernate leisten, ohne dass ich explizit die user als untergebenen hinzufügen muss?

ist ja so auch immer ein restrisiko an inkonsistenzen, falls zwar die beziehung
"user A hat den vorgesetzen X" gelöscht wird, aber die beziehung "vorgesetzer X hat einen untergebenen user A" nicht gelöscht wird.

wenn du mri diese letzte frage noch beantworten könntest, wäre ich wunschlos glücklich
 
Tservarius hat gesagt.:
kann dieses doppelt setzen irgendwie vermieten werden, sprich: kann ich nicht lediglich user.setVorgesetzer(chef) auf basis der users ausführen und die
abfrage untergebenen von einem chef irgendwie über hibernate leisten, ohne dass ich explizit die user als untergebenen hinzufügen muss?

Ich persönlich würde das nicht so machen. Ich wüsste auch nicht wie man es hibernate explizit sagen kann.

MFG

zEriX
 
okay.. noch eine kleine frage zum xml-konfigurationsfile.
was bewirkt der folgende abschnitt eigentlich rein von der logik her?
wie ich gerade sehe wird auf der datenbank selber wird ja kein feld "untergebene" in der tabelle angelegt

eine kurze erklärung wozu dieses mapping da ist wäre nett.

meine derzeitige vermutung - vielleicht ist sie ja auch richtig:
wird ein .getUntergebene() auf ein objekt ausgeführt, verweist dieses in
das hibernate mapping, welches nun die user-tabelle überprüft und alle user'ids zurückgibt, welche das kriterium "vorgesetzer = aktueller user" erfüllen.

wenn dem so ist, würde mich dass allerdings zu meiner vorangegangen frage führen, demnach müsste ich dann doch die untergebenen nicht explizit bei einem chef setzen.

was bewirkt das "inverse=true" ?


Code:
	<bag name="untergebene" inverse="true">
		<key column="vorgesetzter" />
		<one-to-many class="User" />
	</bag>
 
Wenn du schaust, habe ich in der Klasse User eine Liste angelegt in der die Untergebenen gehalten werden. Mit diesem Mapping wird die Liste mit den Untergebenen wieder aufgebaut.

Ok, im Moment ist es eigentlich so wie du es haben möchtest. Also du gibst einfach den Vorgesetzten an. Damit der Vorgesetzte aber die Liste der Untergebenen hat, musst du ihn jedes mal wenn bei einem User der Vorgesetzte gesetzt wird, den Vorgesetzten wieder auslesen.

MFG

zEriX
 
oookkay... habe nun mal einen kleinen test gemacht
(basis ist dein beispiel)

Datenbank Inhalt:
Code:
-- Tabellenstruktur für Tabelle `user`
-- 

CREATE TABLE `user` (
  `userid` int(11) NOT NULL auto_increment,
  `vorname` varchar(255) collate latin1_general_ci default NULL,
  `nachname` varchar(255) collate latin1_general_ci default NULL,
  `vorgesetzter` int(11) default NULL,
  PRIMARY KEY  (`userid`),
  KEY `FK36EBCBD3F17A9B` (`vorgesetzter`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci AUTO_INCREMENT=4 ;

-- 
-- Daten für Tabelle `user`
-- 

INSERT INTO `user` VALUES (1, 'Manfred', 'Mustermann', 3);
INSERT INTO `user` VALUES (2, 'Erika', 'Mustermann', 3);
INSERT INTO `user` VALUES (3, 'Big', 'Chef', NULL);


Habe jetzt ein bisschen Code geschrieben und wollte ein bisschen rumprobieren:
Code:
    	List daten = mgr.listUsers();
    	Iterator it = daten.iterator();
    	while (it.hasNext()) {

    		try {
    		User userobj = (User) it.next();
	    	System.out.println("USER: (" + userobj.getUserid() + ") " + userobj.getVorname() + ' ' + userobj.getNachname());
	    	System.out.println("Vorgesetzer: " + userobj.getVorgesetzter().getVorname() + " " + userobj.getVorgesetzter().getNachname());
	    	System.out.println("Untergebene:" + userobj.getUntergebene().get(0).getVorname() + " " + userobj.getUntergebene().get(0).getNachname());
	    	System.out.println("\n");
    		} catch (Exception e) {
    			System.out.println(e.toString());
    		}
    	}

funktioniert auch alles blendend, nur wenn ich mir die untergebenen (in diesem fall mit dem index 0 ) ausgeben möchte, kommt der folgende error:

Code:
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: eu.xyz.User.untergebene, no session or session was closed


(hoffe ich habs gleich und muss dich nicht mehr nerven :) bin dir jetzt schon unendlich dankbar einen kompetenten ansprechpartner gefunden zu haben)
 
Ich kenne leider deinen Code nicht, aber es liegt daran, dass lazy-Loading für Collections standardmäßig angeschaltet ist. D. h. bei dir werden die Elemente der Liste erst geladen, wenn sie gebraucht werden. Aber bei dir ist die Session dann geschlossen dann können die User nicht mehr nachgeladen werden.
Die einfachste Lösung im Moment wäre lazyLoading einfach abzuschalten.
Code:
<class name="User" lazy="false">

Das ist meiner Meinung nach aber nicht die beste Lösung, weil so sehr viele Daten übertragen werden müssen, auch wenn sie nicht gebraucht werden.

Da ich auch schon länger nichts mehr mit Hibernate gemacht hab, muss ich mir das mal kurz wieder anschauen, dann hab ich vielleich eine Lösung für dich mit lazy-loading.

MFG

zEriX
 
okidoki, jo. bin gespannt :)
ansonsten klappt jetzt alles schon super, wenn du noch was zum "lazy" thema hast, immer her damit.

wenn ich dir auch mal irgendwie im Bereich SEO helfen kann, immer raus damit :)
 
Zurück