# [Hibernate] Relation wird nicht gespeichert (Topic changed)



## sparrow (23. Mrz 2008)

Hallo Forum,

ich steh noch immer ganz am Anfang im Umgang mit Hibernate.
Nun habe ich folgendes Szenario:

Ich stelle auf dem Client ein Objekt zusammen und schicke es via RMI zum Server, dort soll es gespeichert werden.
Das funktioniert, das Objekt wird gespeichert. Allerdings gibt es eine verknüpfte Liste, diese wird leider nicht entsprechend gespeichert. Es gibt keine Fehlermeldung, es gibt nur keinen Anstoß der Speicherung.

Hierbei handelt es sich um die Klasse User die eine Liste aller Gruppe (Group) enthällt in die der User Mitglied ist.

Client:
	
	
	
	





```
private void saveButActionPerformed(java.awt.event.ActionEvent evt) {
    	// A user should been selected
    	if (userList.getSelectedIndex() > -1) {
    		try {
    			// Setting Field-Data
    			UserListModel umodel = (UserListModel) userList.getModel();
    			User u = umodel.getUserAt(userList.getSelectedIndex());
    			u.setUsername(this.usernameField.getText());
    			u.setFullName(this.fullNameField.getText());
    			u.setComment(this.commentField.getText());
    			// Clearing the Groups in the user and setting the new groups from the selected list
    			u.getGroups().clear();
    			int[] selectedIndices = groupList.getSelectedIndices();
    			GroupListModel gml = (GroupListModel) groupList.getModel();
    			for (int i = 0; i < selectedIndices.length; i++) {
    				u.getGroups().add(gml.getGroupAt(selectedIndices[i]));
    				System.out.println("Saving group: " + gml.getGroupAt(selectedIndices[i]));
    			}
    			int saved = userManagment.addOrUpdateUser(u);
    			if (u.getId() == null) {
    				u.setId(saved);
    			}
    			userList.repaint();
    		} catch (RemoteException e) {
    			e.printStackTrace();
    			JOptionPane.showMessageDialog(this, "Failed to connect server for saving: " + e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
    		}
		}
    }
```

Server:
	
	
	
	





```
public int addOrUpdateUser(User user) throws RemoteException {
		Session session = SESSION_FACTORY.openSession();
		Transaction trans = session.beginTransaction();
		try {
			user.setGroups(user.getGroups());
			session.saveOrUpdate(user);
			trans.commit();
			session.close();
			getLogger().info("UserManagmet.addOrUpdateUser saved: " + user.getUsername());
			return user.getId();
		} catch (Exception e) {
			if (trans.isActive()) {
				trans.rollback();
			}
			if (session.isOpen()) {
				session.close();
			}
			getLogger().error("Failed to save User: " + e.getMessage());
			return -1;
		}
	}
```


Die Klasse User:
	
	
	
	





```
@Entity
public class User implements Serializable {

	private List<Group> groups = new ArrayList<Group>();

	@ManyToMany(fetch = FetchType.EAGER)
	public List<Group> getGroups() {
		return groups;
	}
	
	
	public void setGroups(List<Group> groups) {
		this.groups.clear();
		if (groups != null) {
			this.groups.addAll(groups);
		}
	}
	

}
```


Kann mir jemand sagen welchen Fehler ich mache?
Die Liste ist nicht leer wenn sie auf dem Server ankommt sondern korrekt gefüllt.

Vielen Dank schonmal!


Gruß
Sparrow


----------



## SlaterB (23. Mrz 2008)

im Zweifel alles selber speichern oder sich damit auskennen, z.B. ein Lehrbuch lesen 

ich gebe aber mal wieder meinen Halbwissen-Senf dazu bzw zitiere:

http://www.hibernate.org/116.html



> [Frage:] I saved a parent object but its associated objects weren't saved to the database.
> 
> [Antwort:] Associated objects must be saved explicitly by calling Session.save() (or Session.persist()) or the association must be mapped with cascade="all" or cascade="save-update" (or cascade="persist").


----------



## Guest (23. Mrz 2008)

SlaterB hat gesagt.:
			
		

> ich gebe aber mal wieder meinen Halbwissen-Senf dazu bzw zitiere:


Das ist kein Halbwissen, es ist fast die ganze Wahrheit


----------



## sparrow (23. Mrz 2008)

Vielen Dank für den Tipp, leider funktioniert es nicht.

Ich kann eine entsprechende Speicherung der Gruppen vornehmen, es werden dann auch entsprechenden Inserts oder Updates in der Tabelle der Gruppen vorgenommen, jedoch wird die join-table für die Verknüpfung User->Groups nach wie vor nicht gefüllt:


```
public int addOrUpdateUser(User user) throws RemoteException {
		getLogger().info("UserManagmet.addOrUpdateUser saving: " + user.getUsername());
		Session session = SESSION_FACTORY.openSession();
		Transaction trans = session.beginTransaction();
		try {
			for (Group g : user.getGroups()) {
				session.saveOrUpdate(g);
				getLogger().info("Saving group: " + g);
			}
			session.saveOrUpdate(user);
			trans.commit();
			session.close();
			getLogger().info("UserManagmet.addOrUpdateUser saved: " + user.getUsername());
			return user.getId();
		} catch (Exception e) {
			if (trans.isActive()) {
				trans.rollback();
			}
			if (session.isOpen()) {
				session.close();
			}
			getLogger().error("Failed to save User: " + e.getMessage());
			return -1;
		}
	}
```


----------



## maki (23. Mrz 2008)

Setze die cascade richtig, nämlich save-update.

Selbst jedes Objekt einzeln zu speichern ist eher selten.


----------



## sparrow (23. Mrz 2008)

```
@ManyToMany(fetch = FetchType.EAGER)
	@Cascade(CascadeType.SAVE_UPDATE)
	public List<Group> getGroups() {
		return groups;
	}
```

Leider keine Änderung


----------



## SlaterB (24. Mrz 2008)

wo in deinen Mappings wird denn die Join-Table explizit genannt/ konfiguriert?
ich persönlich weiß nicht wie es geht, von allein wird sich Hibernate aber nicht nach irgendwelchen Tabellen in der DB umschauen


----------



## byte (24. Mrz 2008)

Slater hat Recht. Du hast nirgends angegeben, wie das ManyToMany gemappt ist. Wenn es z.B. per Zwischentabelle passiert, dann gib dieses Mapping an mit @JoinTable.


----------



## sparrow (24. Mrz 2008)

Hibernate braucht sich auch nicht nach irgendwelchen Tabellen umschauen da ich keinerlei Tabellen vorgebe sondern alles von Hibernate managen, anlegen und verwalten lassen.

Wird kein @JoinTable angegeben verwendet Hibernate standardmäßig einen Tabellennamen der sich aus dem Tabellennamen der beiden verknüpften Tabellen zusammen setzt, als Fremdschlüssel werden hier die jeweiligen Schlüssel der Verknüpften Tabellen benutzt.


```
/**
	 * Returns a List with all Groups of the user
	 * @return a List with all Groups of the user
	 */
	@ManyToMany(fetch = FetchType.EAGER)
	@Cascade(CascadeType.SAVE_UPDATE)
	@JoinTable(name = "core_user_groups_rel", 
			joinColumns = {@JoinColumn(name = "user_fk")}, 
			inverseJoinColumns = {@JoinColumn(name = "group_fg")})
	public List<Group> getGroups() {
		return groups;
	}
```
Dieser Code legt die gewünschte Tabelle an, aber auch hier werden keine Eintragungen der Relationen vorgenommen. Sobald ich allerdings von Hand einen Eintrag in die Tabelle einfüge (_INSERT INTO CORE_USER_GROUPS_REL VALUES(1, 2)_) ist anschließend auch bei einem Abruf eine Liste zurück gegeben die die Gruppe enthält. Grundsätzlich funktioniert es also, nur wird die Relation nicht wie gewünscht befüllt.

Hier noch einmal die Methode die speichern soll:
	
	
	
	





```
public int addOrUpdateUser(User user) throws RemoteException {
		getLogger().info("UserManagmet.addOrUpdateUser saving: " + user.getUsername());
		Session session = SESSION_FACTORY.openSession();
		Transaction trans = session.beginTransaction();
		try {
			for (Group g : user.getGroups()) {
				session.saveOrUpdate(g);
				getLogger().info("Saving group: " + g);
			}
			session.saveOrUpdate(user);
			trans.commit();
			session.close();
			getLogger().info("UserManagmet.addOrUpdateUser saved: " + user.getUsername());
			return user.getId();
		} catch (Exception e) {
			if (trans.isActive()) {
				trans.rollback();
			}
			if (session.isOpen()) {
				session.close();
			}
			getLogger().error("Failed to save User: " + e.getMessage());
			return -1;
		}
	}
```

Hibernate gibt beim Speichern folgende DEBUG-Informationen aus, vielleicht kann daraus ja jemand etwas sehen:
	
	
	
	





```
INFO - UserManagmet.addOrUpdateUser saving: sparrow
DEBUG - opened session at timestamp: 12063899741
DEBUG - begin
DEBUG - opening JDBC connection
DEBUG - total checked-out connections: 0
DEBUG - using pooled JDBC connection, pool size: 0
DEBUG - current autocommit status: false
DEBUG - after transaction begin
DEBUG - id unsaved-value: null
DEBUG - detached instance of: core.common.userManagment.Group
DEBUG - updating detached instance
DEBUG - updating [core.common.userManagment.Group#2]
DEBUG - updating [core.common.userManagment.Group#2]
INFO - Saving group: 2
DEBUG - transient instance of: core.common.userManagment.User
DEBUG - saving transient instance
DEBUG - saving [core.common.userManagment.User#<null>]
DEBUG - executing insertions
DEBUG - processing cascade ACTION_SAVE_UPDATE for: core.common.userManagment.User
DEBUG - done processing cascade ACTION_SAVE_UPDATE for: core.common.userManagment.User
DEBUG - Wrapped collection in role: core.common.userManagment.User.groups
DEBUG - executing identity-insert immediately
DEBUG - Inserting entity: core.common.userManagment.User (native id)
DEBUG - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
DEBUG -
    insert
    into
        core_user
        (id, comment, fullName, password, username)
    values
        (null, ?, ?, ?, ?)
Hibernate:
    insert
    into
        core_user
        (id, comment, fullName, password, username)
    values
        (null, ?, ?, ?, ?)
DEBUG - preparing statement
DEBUG - Dehydrating entity: [core.common.userManagment.User#<null>]
DEBUG - binding 'test' to parameter: 1
DEBUG - binding 'Sparrow' to parameter: 2
DEBUG - binding null to parameter: 3
DEBUG - binding 'sparrow' to parameter: 4
DEBUG - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
DEBUG - closing statement
DEBUG - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
DEBUG -
    call identity()
Hibernate:
    call identity()
DEBUG - preparing statement
DEBUG - Natively generated identity: 1
DEBUG - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
DEBUG - closing statement
DEBUG - processing cascade ACTION_SAVE_UPDATE for: core.common.userManagment.User
DEBUG - cascade ACTION_SAVE_UPDATE for collection: core.common.userManagment.User.groups
DEBUG - done cascade ACTION_SAVE_UPDATE for collection: core.common.userManagment.User.groups
DEBUG - done processing cascade ACTION_SAVE_UPDATE for: core.common.userManagment.User
DEBUG - commit
DEBUG - automatically flushing session
DEBUG - flushing session
DEBUG - processing flush-time cascades
DEBUG - processing cascade ACTION_SAVE_UPDATE for: core.common.userManagment.User
DEBUG - cascade ACTION_SAVE_UPDATE for collection: core.common.userManagment.User.groups
DEBUG - done cascade ACTION_SAVE_UPDATE for collection: core.common.userManagment.User.groups
DEBUG - done processing cascade ACTION_SAVE_UPDATE for: core.common.userManagment.User
DEBUG - dirty checking collections
DEBUG - Flushing entities and processing referenced collections
DEBUG - Updating entity: [core.common.userManagment.Group#2]
DEBUG - Wrapped collection in role: core.common.userManagment.User.groups
DEBUG - Collection found: [core.common.userManagment.User.groups#1], was: [<unreferenced>] (initialized)
DEBUG - Processing unreferenced collections
DEBUG - Found collection with unloaded owner: [<unreferenced>]
DEBUG - Scheduling collection removes/(re)creates/updates
DEBUG - Flushed: 0 insertions, 1 updates, 0 deletions to 2 objects
DEBUG - Flushed: 1 (re)creations, 0 updates, 0 removals to 2 collections
DEBUG - listing entities:
DEBUG - core.common.userManagment.User{id=1, username=sparrow, fullName=Sparrow, comment=test, password=null, groups=[]}
DEBUG - core.common.userManagment.Group{id=2, groupname=2}
DEBUG - executing flush
DEBUG - registering flush begin
DEBUG - Updating entity: [core.common.userManagment.Group#2]
DEBUG - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
DEBUG -
    update
        core_group
    set
        groupname=?
    where
        id=?
Hibernate:
    update
        core_group
    set
        groupname=?
    where
        id=?
DEBUG - preparing statement
DEBUG - Dehydrating entity: [core.common.userManagment.Group#2]
DEBUG - binding '2' to parameter: 1
DEBUG - binding '2' to parameter: 2
DEBUG - Executing batch size: 1
DEBUG - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
DEBUG - closing statement
DEBUG - Inserting collection: [core.common.userManagment.User.groups#1]
DEBUG - collection was empty
DEBUG - registering flush end
DEBUG - post flush
DEBUG - before transaction completion
DEBUG - before transaction completion
DEBUG - committed JDBC Connection
DEBUG - after transaction completion
DEBUG - aggressively releasing JDBC connection
DEBUG - releasing JDBC connection [ (open PreparedStatements: 0, globally: 0) (open ResultSets: 0, globally: 0)]
DEBUG - returning connection to pool, pool size: 1
DEBUG - after transaction completion
DEBUG - closing session
DEBUG - connection already null in cleanup : no action
INFO - UserManagmet.addOrUpdateUser saved: sparrow
```

Mir geht einfach kein Licht auf woran es liegt.


----------



## sparrow (25. Mrz 2008)

Hmm... es will einfach nicht.
Ich hab gedacht es könnte vielleicht noch daran liegen, dass ich die Gruppen im Client adde, aber auch wenn ich das Objekt einfach auf dem Server erzeuge funktioniert es nicht.

Hier noch einmal zu Übersicht die Methode die speichert und die Klasse.

Vielleicht fällt ja noch jemanden etwas auf.


Gruß
Sparrow

Die Methode zum speichern:
	
	
	
	





```
public int addOrUpdateUser() throws RemoteException {
		User u = new User();
		Group g1 = new Group();
		g1.setGroupname("group1");
		Group g2 = new Group();
		g1.setGroupname("group2");
		u.setUsername("testuser");
		u.setFullName("Test User");
		u.getGroups().add(g1);
		u.getGroups().add(g2);
		getLogger().info("UserManagmet.addOrUpdateUser saving: " + u.getUsername());
		Session session = SESSION_FACTORY.openSession();
		Transaction trans = session.beginTransaction();
		try {
			for (Group g : u.getGroups()) {
				session.saveOrUpdate(g);
				getLogger().info("Saving group: " + g);
			}
			session.saveOrUpdate(u);
			trans.commit();
			session.close();
			getLogger().info("UserManagmet.addOrUpdateUser saved: " + u.getUsername());
			return u.getId();
		} catch (Exception e) {
			if (trans.isActive()) {
				trans.rollback();
			}
			if (session.isOpen()) {
				session.close();
			}
			Marmota.getLogger().error("Failed to save User: " + e.getMessage());
			return -1;
		}
```


Die Klasse User

```
@Entity
@Table(name = "core_user")
public class User implements Serializable {

	private static final long serialVersionUID = 1621422576067196991L;
	private String comment;
	private String fullName;
	private List<Group> groups = new ArrayList<Group>();
	private Integer id;
	private String password;
	private String username;
	
	/**
	 * @return The comment
	 */
	@Column
	public String getComment() {
		return comment;
	}
	
	/**
	 * @return The Fulname of the user
	 */
	@Column
	public String getFullName() {
		return fullName;
	}
	
	/**
	 * Returns a List with all Groups of the user
	 * @return a List with all Groups of the user
	 */
	@ManyToMany(fetch = FetchType.EAGER)
	@Cascade(CascadeType.SAVE_UPDATE)
	@JoinTable(name = "core_user_groups_rel", 
			joinColumns = {@JoinColumn(name = "user_fk")}, 
			inverseJoinColumns = {@JoinColumn(name = "group_fg")})
	public List<Group> getGroups() {
		return groups;
	}
	
	/**
	 * @return The ID of the user
	*/
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	public Integer getId() {
		return id;
	}
	
	/**
	 * @return The password for the user
	 */
	@Column
	public String getPassword() {
		return password;
	}
	
	/**
	 * @return The username for the user
	 */
	@Column
	public String getUsername() {
		return username;
	}
	
	public void setComment(String comment) {
		this.comment = comment;
	}
	
	public void setFullName(String fullName) {
		this.fullName = fullName;
	}
	
	public void setGroups(List<Group> groups) {
		this.groups.clear();
		if (groups != null) {
			this.groups.addAll(groups);
		}
	}
	
	public void setId(Integer id) {
		this.id = id;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public void setUsername(String username) {
		this.username = username;
	}
	

	/** 
	 * Overrides the "toString" Method to get the Username
	 * when the method is called
	 * @see java.lang.Object#toString()
	 */
	@Transient
	public String toString() {
		return this.getUsername();
	}
	

}
```


Und die Klasse Group
	
	
	
	





```
@Entity
@Table(name = "core_group")
public class Group implements Serializable {
	
	private static final long serialVersionUID = 6758531307415539352L;

	private Integer id;
	
	private String groupname;

	
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	public Integer getId() {
		return id;
	}

	@Column
	public void setId(Integer id) {
		this.id = id;
	}

	public String getGroupname() {
		return groupname;
	}

	public void setGroupname(String groupname) {
		this.groupname = groupname;
	}
	
	
	/** 
	 * Overrides the Method to get the groupname
	 * if the method is called
	 * @see java.lang.Object#toString()
	 */
	@Transient
	public String toString() {
		return this.getGroupname();
	}

}
```


----------



## SnooP (26. Mrz 2008)

Hm... ich seh nischts... - aber mach mal das @Column bei der setId weg und versuch mal in die getter/setter nen breakpoint zu setzen und guck, was da so passiert im Einzelnen.


----------



## sparrow (27. Mrz 2008)

Ah stimmt, das @Column war falsch in Group.
Leider ist das Problem noch immer vorhanden.

Was genau meinst du mit breakpoints setzen? Meldungen ausgeben lassen?


----------

