-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 18 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: Newbie collection problem
PostPosted: Fri Feb 24, 2006 6:47 am 
Newbie

Joined: Fri Feb 24, 2006 5:38 am
Posts: 11
I just started out with NHibernate and C#.
I wanted to try NHibernate with remoting and got it to work fine, except for 1 thing.

I have two entities User and Character with a many-to-one relationship.
The User class contains a collection of Character objects.

First the client gets a User object from the server.
Then I create a new Character object and add it to the User collection.
I save the Character and everything looks great in the db.
The problem is that the collection doesnt contain the new character object! Why??


Client code:
Code:
User _user = server.getUser(username); // Get the user from the db which already has 2 characters
Character _char = new Character(); // Create new character
_char.Name = "test";
_char.Owner = _user;
_user.Characters.Add(_char); // Add character to user...wrong way??

server.saveObject(_char); // This saves the character to the db and the link aswell, the user has now 3 characters in the db

foreach(Character c in _user.Character)
   listBox1.Items.Add(c.Name); // Only returns 2!!!


Mappings:
Code:
<class name="DBLib.DataObject.User, DBLib" table="COT_USER">
   <id   name="Id" column="ID" type="Int32" unsaved-value="0">
      <generator class="identity" />
   </id>
   <property name="Username" type="String" length="10" column="USERNAME" />
   <property name="Password" type="String" length="10" column="PASSWORD" />
   <property name="Online" type="Int32" column="ONLINE" />
   <many-to-one class="DBLib.DataObject.UserLevel, DBLib" name="Level" column="USERLEVEL_ID" />
   <set name="Characters" table="COT_CHARACTER" cascade="none" lazy="false" inverse="true">
      <key column="USER_ID" />
      <one-to-many class="DBLib.DataObject.Character, DBLib" />
   </set>   
</class>

<class name="DBLib.DataObject.Character, DBLib" table="COT_CHARACTER">
   <id   name="Id" column="ID" type="Int32" unsaved-value="0">
      <generator class="identity" />
   </id>
   <property name="Name" type="String" length="30" column="NAME" />
   <property name="Stat1" type="Int32" column="STAT1" />
   <property name="Stat2" type="Int32" column="STAT2" />
   <property name="Stat3" type="Int32" column="STAT3" />
   <many-to-one class="DBLib.DataObject.User, DBLib" name="Owner" column="USER_ID" not-null="true"/>
   <set name="Items" table="REL_CHARACTER_ITEM" cascade="none" lazy="false" inverse="true">
      <key column="CHARACTER_ID" />
      <many-to-many class="DBLib.DataObject.Item, DBLib" column="ITEM_ID" />
   </set>
</class>


Entity classes:
Code:
[Serializable()]
public class User : MarshalByRefObject
{
   int _id;
   string _username;
   string _password;
   int _online;
   UserLevel _level;
   ISet _characters;

   public User() {}

   public int Id
   {
      get { return _id;}
      set { _id = value;}
   }

   public string Username
   {
      get { return _username;}
      set { _username = value;}
   }

   public string Password
   {
      get { return _password;}
      set { _password = value;}
   }

   public UserLevel Level
   {
      get { return _level;}
      set { _level = value;}
   }

   public int Online
   {
      get { return _online; }
      set { _online = value; }
   }

   public ISet Characters
   {
      get
      {
         if (_characters == null)
            _characters = new HashedSet();
         return _characters;
      }
      set { _characters = value; }
   }

   public override string ToString()
   {
      return _username;
   }

}


[Serializable()]
public class Character : MarshalByRefObject
{
   int _id;
   string _name;
   int _stat1;
   int _stat2;
   int _stat3;
   User _owner;
   ISet _items;

   public Character() {}

   public int Id
   {
      get { return _id;}
      set { _id = value;}
   }

   public string Name
   {
      get { return _name;}
      set { _name = value;}
   }

   public int Stat1
   {
      get { return _stat1;}
      set { _stat1 = value;}
   }

   public int Stat2
   {
      get { return _stat2;}
      set { _stat2 = value;}
   }

   public int Stat3
   {
      get { return _stat3;}
      set { _stat3 = value;}
   }

   public User Owner
   {
      get { return _owner;}
      set { _owner = value;}
   }

   public ISet Items
   {
      get
      {
         if (_items == null)
            _items = new HashedSet();
         return _items;
      }
      set { _items = value; }
   }

   public override string ToString()
   {
      return _name;
   }
}


Top
 Profile  
 
 Post subject:
PostPosted: Fri Feb 24, 2006 12:13 pm 
Contributor
Contributor

Joined: Thu May 12, 2005 8:45 am
Posts: 226
You might want to enable log4net and see what the logs say. http://www.hibernate.org/364.html


Top
 Profile  
 
 Post subject:
PostPosted: Mon Feb 27, 2006 5:44 am 
Newbie

Joined: Fri Feb 24, 2006 5:38 am
Posts: 11
I have checked the log and to me it's seems ok. But again, the objects are stored correctly in the DB. I think this is more a collection-usage-problem for my side, or maybe a remoting problem.

Here's what the log says:


2006-02-27 10:33:32,264 [2756] DEBUG NHibernate.Impl.SessionImpl [(null)] - opened session
2006-02-27 10:33:32,483 [2756] DEBUG NHibernate.Engine.Cascades [(null)] - unsaved-value: 0
2006-02-27 10:33:32,483 [2756] DEBUG NHibernate.Impl.SessionImpl [(null)] - SaveOrUpdate() unsaved instance
2006-02-27 10:33:32,483 [2756] DEBUG NHibernate.Impl.SessionImpl [(null)] - saving [DBLib.DataObject.Character#<null>]
2006-02-27 10:33:32,483 [2756] DEBUG NHibernate.Impl.SessionImpl [(null)] - executing insertions
2006-02-27 10:33:32,499 [2756] DEBUG NHibernate.Impl.WrapVisitor [(null)] - Wrapped collection in role: DBLib.DataObject.Character.Items
2006-02-27 10:33:32,514 [2756] DEBUG NHibernate.Engine.Cascades [(null)] - unsaved-value: 0
2006-02-27 10:33:32,514 [2756] DEBUG NHibernate.Persister.EntityPersister [(null)] - Inserting entity: DBLib.DataObject.Character (native id)
2006-02-27 10:33:32,514 [2756] DEBUG NHibernate.Impl.BatcherImpl [(null)] - Opened new IDbCommand, open IDbCommands :1
2006-02-27 10:33:32,514 [2756] DEBUG NHibernate.Impl.BatcherImpl [(null)] - Building an IDbCommand object for the SqlString: INSERT INTO COT_CHARACTER (USER_ID, STAT1, NAME, STAT3, STAT2, ID) VALUES (:USER_ID, :STAT1, :NAME, :STAT3, :STAT2, default)
2006-02-27 10:33:32,514 [2756] DEBUG NHibernate.Persister.EntityPersister [(null)] - Dehydrating entity: [DBLib.DataObject.Character#<null>]
2006-02-27 10:33:32,514 [2756] DEBUG NHibernate.Engine.Cascades [(null)] - unsaved-value: 0
2006-02-27 10:33:32,514 [2756] DEBUG NHibernate.Type.Int32Type [(null)] - binding '1' to parameter: 0
2006-02-27 10:33:32,514 [2756] DEBUG NHibernate.Type.Int32Type [(null)] - binding '5' to parameter: 1
2006-02-27 10:33:32,514 [2756] DEBUG NHibernate.Type.StringType [(null)] - binding 'TestChar' to parameter: 2
2006-02-27 10:33:32,514 [2756] DEBUG NHibernate.Type.Int32Type [(null)] - binding '5' to parameter: 3
2006-02-27 10:33:32,514 [2756] DEBUG NHibernate.Type.Int32Type [(null)] - binding '5' to parameter: 4
2006-02-27 10:33:32,514 [2756] DEBUG NHibernate.SQL [(null)] - INSERT INTO COT_CHARACTER (USER_ID, STAT1, NAME, STAT3, STAT2, ID) VALUES (?, ?, ?, ?, ?, default)
2006-02-27 10:33:32,514 [2756] DEBUG NHibernate.SQL [(null)] - p0 = '1'
2006-02-27 10:33:32,514 [2756] DEBUG NHibernate.SQL [(null)] - p1 = '5'
2006-02-27 10:33:32,514 [2756] DEBUG NHibernate.SQL [(null)] - p2 = 'TestChar'
2006-02-27 10:33:32,514 [2756] DEBUG NHibernate.SQL [(null)] - p3 = '5'
2006-02-27 10:33:32,514 [2756] DEBUG NHibernate.SQL [(null)] - p4 = '5'
2006-02-27 10:33:32,514 [2756] DEBUG NHibernate.Connection.DriverConnectionProvider [(null)] - Obtaining IDbConnection from Driver
2006-02-27 10:33:33,092 [2756] DEBUG NHibernate.Impl.BatcherImpl [(null)] - Closed IDbCommand, open IDbCommands :0
2006-02-27 10:33:33,092 [2756] DEBUG NHibernate.Impl.BatcherImpl [(null)] - Opened new IDbCommand, open IDbCommands :1
2006-02-27 10:33:33,092 [2756] DEBUG NHibernate.Impl.BatcherImpl [(null)] - Building an IDbCommand object for the SqlString: values IDENTITY_VAL_LOCAL()
2006-02-27 10:33:33,092 [2756] DEBUG NHibernate.SQL [(null)] - values IDENTITY_VAL_LOCAL()
2006-02-27 10:33:33,092 [2756] DEBUG NHibernate.Impl.BatcherImpl [(null)] - Opened Reader, open Readers :1
2006-02-27 10:33:33,092 [2756] DEBUG NHibernate.Persister.AbstractEntityPersister [(null)] - Natively generated identity: 22
2006-02-27 10:33:33,092 [2756] DEBUG NHibernate.Impl.BatcherImpl [(null)] - Closed Reader, open Readers :0
2006-02-27 10:33:33,092 [2756] DEBUG NHibernate.Impl.BatcherImpl [(null)] - Closed IDbCommand, open IDbCommands :0
2006-02-27 10:33:33,092 [2756] DEBUG NHibernate.Impl.SessionImpl [(null)] - flushing session
2006-02-27 10:33:33,092 [2756] DEBUG NHibernate.Impl.SessionImpl [(null)] - Flushing entities and processing referenced collections
2006-02-27 10:33:33,108 [2756] DEBUG NHibernate.Impl.AbstractVisitor [(null)] - Processing collection for role DBLib.DataObject.Character.Items
2006-02-27 10:33:33,108 [2756] DEBUG NHibernate.Impl.SessionImpl [(null)] - Collection found: [DBLib.DataObject.Character.Items#22], was: [<unreferenced>]
2006-02-27 10:33:33,108 [2756] DEBUG NHibernate.Impl.SessionImpl [(null)] - Processing unreferenced collections
2006-02-27 10:33:33,108 [2756] DEBUG NHibernate.Impl.SessionImpl [(null)] - scheduling collection removes/(re)creates/updates
2006-02-27 10:33:33,108 [2756] DEBUG NHibernate.Impl.SessionImpl [(null)] - Flushed: 0 insertions, 0 updates, 0 deletions to 1 objects
2006-02-27 10:33:33,108 [2756] DEBUG NHibernate.Impl.SessionImpl [(null)] - Flushed: 1 (re)creations, 0 updates, 0 removals to 2 collections
2006-02-27 10:33:33,108 [2756] DEBUG NHibernate.Impl.Printer [(null)] - listing entities:
2006-02-27 10:33:33,124 [2756] DEBUG NHibernate.Impl.Printer [(null)] - DBLib.DataObject.Character{Id=22, Owner=User#1, Stat1=5, Name=TestChar, Stat3=5, Items=[], Stat2=5}
2006-02-27 10:33:33,124 [2756] DEBUG NHibernate.Impl.SessionImpl [(null)] - executing flush
2006-02-27 10:33:33,124 [2756] DEBUG NHibernate.Impl.SessionImpl [(null)] - post flush
2006-02-27 10:33:33,124 [2756] DEBUG NHibernate.Impl.SessionImpl [(null)] - closing session
2006-02-27 10:33:33,124 [2756] DEBUG NHibernate.Impl.SessionImpl [(null)] - disconnecting session
2006-02-27 10:33:33,124 [2756] DEBUG NHibernate.Connection.ConnectionProvider [(null)] - Closing connection
2006-02-27 10:33:33,124 [2756] DEBUG NHibernate.Impl.SessionImpl [(null)] - transaction completion


Top
 Profile  
 
 Post subject: cascade
PostPosted: Mon Feb 27, 2006 7:14 am 
Regular
Regular

Joined: Tue Jan 03, 2006 7:21 am
Posts: 85
Can you try:

server.SaveObject(_user) and use cascade="save-update" for the Characters collection of the User class. Does this work correctly then?


Top
 Profile  
 
 Post subject:
PostPosted: Mon Feb 27, 2006 8:34 am 
Newbie

Joined: Fri Feb 24, 2006 5:38 am
Posts: 11
Thanks for the answer, but that does not work.
The character does not get saved at all in the db, and the collection problem remains...


Top
 Profile  
 
 Post subject: Re: Newbie collection problem
PostPosted: Mon Feb 27, 2006 9:11 am 
Expert
Expert

Joined: Thu Jan 19, 2006 4:29 pm
Posts: 348
u11113901 wrote:

First the client gets a User object from the server.
Then I create a new Character object and add it to the User collection.
I save the Character and everything looks great in the db.
The problem is that the collection doesnt contain the new character object! Why??


Client code:
Code:
User _user = server.getUser(username); // Get the user from the db which already has 2 characters
Character _char = new Character(); // Create new character
_char.Name = "test";
_char.Owner = _user;
_user.Characters.Add(_char); // Add character to user...wrong way??

server.saveObject(_char); // This saves the character to the db and the link aswell, the user has now 3 characters in the db

foreach(Character c in _user.Character)
   listBox1.Items.Add(c.Name); // Only returns 2!!!



Does the _user.Characters contain newly created charactre before the "server.save(_char)" method call? Immediately after "_user.Characters.Add(_char)" method call?

Gert


Top
 Profile  
 
 Post subject:
PostPosted: Mon Feb 27, 2006 10:07 am 
Newbie

Joined: Fri Feb 24, 2006 5:38 am
Posts: 11
No it do not...


Top
 Profile  
 
 Post subject:
PostPosted: Mon Feb 27, 2006 10:23 am 
Expert
Expert

Joined: Thu Jan 19, 2006 4:29 pm
Posts: 348
u11113901 wrote:
No it do not...


Funny... What is the return value of _user.Characters.Add(_char);? True or false?

If false, the ISet thinks for some reason that given character is already in set.

Gert


Top
 Profile  
 
 Post subject:
PostPosted: Mon Feb 27, 2006 10:51 am 
Newbie

Joined: Fri Feb 24, 2006 5:38 am
Posts: 11
The .Add method returns True

Am I using the ISet correctly?
Do I need to make my own list?
Or does not ISet support remoting?


Top
 Profile  
 
 Post subject:
PostPosted: Mon Feb 27, 2006 11:50 am 
Expert
Expert

Joined: Thu Jan 19, 2006 4:29 pm
Posts: 348
u11113901 wrote:
The .Add method returns True

Am I using the ISet correctly?
Do I need to make my own list?
Or does not ISet support remoting?


I do not know. I have made a chatty service interface once (I was using Delphi) and after that I only use service-based (chunky) interfaces.
Improving .NET Application Performance and Scalability

Anyway, the ISet is declared as

public interface ISet : ICollection, ICloneable

and Set as

[Serializable]
public abstract class Set : ISet

And no additional effort to make it work with remoting. You could test out how well it works.. (And post results here, it would be intresting to know)

Gert


Top
 Profile  
 
 Post subject:
PostPosted: Tue Feb 28, 2006 8:12 am 
Newbie

Joined: Fri Feb 24, 2006 5:38 am
Posts: 11
I have been testing around a bit with different lists and mappings, but the problem remains.
Another thing that bugs me:
I have a many-to-many relationship between the Character entity and an Item entity. Both have a ISet collection.
If I create a new Item entity in the client and just save it, the relation is not saved.
In order to have the relation saved I must add the Character to the collection for my new Item entity.
So here the ISet.Add works!
Strange that I can not add the Item to the collection for the Character...
Does all this depend on how you map the entities?

The client code:
Code:
Character c = (Character) characterListBox.SelectedItem;
Item _item = new Item();
_item.Name = itemNameBox.Text;
_item.Type = (ItemType) itemTypeComboBox.SelectedItem;

_item.Characters.Add(c); // required for the relation to be saved, and c is added to the collection
c.Items.Add(_item);      // No effect! _item is not added to the collection
server.saveObject(_item);  // Saves the item and relation


Item mapping:
Code:
<class name="DBLib.DataObject.Item, DBLib" table="COT_ITEM">
   <id   name="Id" column="ID" type="Int32" unsaved-value="0">
      <generator class="identity" />
   </id>
   <property name="Name" type="String" length="30" column="NAME" />
   <many-to-one class="DBLib.DataObject.ItemType, DBLib" name="Type" column="ITEMTYPE_ID"/>
   <set name="Characters" table="REL_CHARACTER_ITEM" cascade="none" lazy="false" inverse="false">
      <key column="ITEM_ID" />
      <many-to-many class="DBLib.DataObject.Character, DBLib" column="CHARACTER_ID" />
   </set>
</class>


If I create a new Character in my client and add a new created Item to that Character, there is no collection problem. Both collections will then hold each others object. The problem occur trying to add a new Item to a Character being loaded from the server.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Feb 28, 2006 9:44 am 
Expert
Expert

Joined: Thu Jan 19, 2006 4:29 pm
Posts: 348
u11113901 wrote:
Does all this depend on how you map the entities?


Propably. The <inverse="true|false"> controls which entity is responsible for storing relation in database. If <inverse="true"> the the resposibility is delegated to another end of relation. If both ends have <inverse="true"> then no-one will persist the relation.

Gert


Top
 Profile  
 
 Post subject: Re: Newbie collection problem
PostPosted: Tue Feb 28, 2006 2:46 pm 
Newbie

Joined: Thu Feb 02, 2006 7:36 pm
Posts: 1
I think NHibernate does not attach collections until you refresh or save User.

Session.Refresh(user,NHibernate.LockMode.None);


Top
 Profile  
 
 Post subject:
PostPosted: Wed Mar 01, 2006 9:41 am 
Newbie

Joined: Fri Feb 24, 2006 5:38 am
Posts: 11
The collection problem definetly depends on remoting.
I removed, by mistake, the "MarshalByRefObject" on my entity objects and suddenly the collections worked!
The problem with that approach is that the entity id:s does not get updated when i save new objects (I use identity).
So I can create a new Character and add it to an existing User.
If I then list my characters on the User, it will exist.
But now I can not add an Item to my Character since my character does not have a correct id.

If I put back the "MarshalByRefObject" on my entities the id mechanism works, but then the collection problem reappears.

Is there a way to solve this?


Top
 Profile  
 
 Post subject:
PostPosted: Wed Mar 01, 2006 10:10 am 
Newbie

Joined: Fri Feb 24, 2006 5:38 am
Posts: 11
ok, the solution was simple. I make the server return the id of the saved item.
server.saveObject(Object o) returns the id and I update the object id on the client side.
Now the collections work and I can update my objects.
I do not know if this is the right way, but it works.
Thanks for all help.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 18 posts ]  Go to page 1, 2  Next

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.