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.  [ 6 posts ] 
Author Message
 Post subject: Many-to-many cascade will not insert non-existant record
PostPosted: Wed Feb 04, 2009 6:05 pm 
Newbie

Joined: Wed Feb 04, 2009 5:53 pm
Posts: 5
I have a Zone <-> Sensor M;N Relation and they are mapped the following way:

Code:
<class name="Zone" table="zones">

      <id name="Num" column="zoneId" type="Int32">
         <generator class="assigned"/>
      </id>
      <property column="zoneName" type="String" name="Name" not-null="true" length="256" />
      <property column="enabled" type="Boolean" name="Enabled" not-null="true" />
      <bag name="AssignedSensors" table="SensorsInZones" lazy="false" inverse="true" >
         <key column="ZoneId"></key>
         <many-to-many class="Sensor" column="SensorId"></many-to-many>
      </bag>

   </class>


Code:
<class name="Sensor" table="sensors">

      <id name="Id" column="SensorId" type="Int32">
         <generator class="assigned"/>
      </id>
      <property column="address" type="String" name="Address" not-null="true" length="256" />
      <property column="enabled" type="Boolean" name="Enabled" not-null="true" />
      <bag name="AssignedZones" table="SensorsInZones" cascade="save-update" >
         <key column="SensorId"></key>
         <many-to-many class="Zone" column="ZoneId"></many-to-many>
      </bag>
   </class>


I have a unit test set to create a sensor and then create a zone as part of that sensor's assigned zone.

Here is the Sensor Class's members:
Code:
private string address;
   protected PropertyChangedEventHandler _propertyChanged;
 
   private IList<Zone> assignedZones;

        private bool enabled;

        private int id;


And here is the unit test code:
Code:
Repository repo;
         Sensor testSensor = new Sensor();
         using (repo = new Repository(RepositoryMode.Updatable))
         {
            WeatherInfoFetcher weatherQuery = new WeatherInfoFetcher();
            testSensor.Id = 1234;
            testSensor.Address = "123.45.67.89";
            testSensor.Enabled = true;
            
            Zone testZone = new Zone();
            testZone.Num = 1;
            testZone.Name = "Front Yard";
            testZone.Enabled = true;
            testSensor.AssignedZones.Add(testZone);
            repo.SensorDAO.Insert(testSensor);
}

Here are my errors:
Code:
WeatherInfo.UnitTest.DALFixture.SensorDAOTest:
NHibernate.StaleStateException : Unexpected row count: 0; expected: 1


Code:
NHibernate: INSERT INTO sensors (address, enabled, SensorId) VALUES (@p0, @p1, @p2); @p0 = '123.45.67.89', @p1 = 'True', @p2 = '1234'
NHibernate: UPDATE zones SET zoneName = @p0, enabled = @p1 WHERE zoneId = @p2; @p0 = 'Front Yard', @p1 = 'True', @p2 = '1'


Code:
17:00:33,952 ERROR [TestRunnerThread] AbstractFlushingEventListener [(null)]- Could not synchronize database state with session
NHibernate.StaleStateException: Unexpected row count: 0; expected: 1

   at NHibernate.AdoNet.Expectations.BasicExpectation.VerifyOutcomeNonBatched(Int32 rowCount, IDbCommand statement)

   at NHibernate.AdoNet.NonBatchingBatcher.AddToBatch(IExpectation expectation)

   at NHibernate.Persister.Entity.AbstractEntityPersister.Update(Object id, Object[] fields, Object[] oldFields, Object rowId, Boolean[] includeProperty, Int32 j, Object oldVersion, Object obj, SqlCommandInfo sql, ISessionImplementor session)

   at NHibernate.Persister.Entity.AbstractEntityPersister.UpdateOrInsert(Object id, Object[] fields, Object[] oldFields, Object rowId, Boolean[] includeProperty, Int32 j, Object oldVersion, Object obj, SqlCommandInfo sql, ISessionImplementor session)

   at NHibernate.Persister.Entity.AbstractEntityPersister.Update(Object id, Object[] fields, Int32[] dirtyFields, Boolean hasDirtyCollection, Object[] oldFields, Object oldVersion, Object obj, Object rowId, ISessionImplementor session)

   at NHibernate.Action.EntityUpdateAction.Execute()

   at NHibernate.Engine.ActionQueue.Execute(IExecutable executable)

   at NHibernate.Engine.ActionQueue.ExecuteActions(IList list)

   at NHibernate.Engine.ActionQueue.ExecuteActions()

   at NHibernate.Event.Default.AbstractFlushingEventListener.PerformExecutions(IEventSource session)



Any idea what the problem is??


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 04, 2009 6:09 pm 
Newbie

Joined: Wed Feb 04, 2009 5:53 pm
Posts: 5
And I have a related question: Will there be a cyclic retrieval when retrieving either class? Because Zones contain Sensors contain Sensors...etc. How does NHibernate handle that gracefully


Top
 Profile  
 
 Post subject:
PostPosted: Thu Feb 05, 2009 3:59 am 
Expert
Expert

Joined: Thu Dec 14, 2006 5:57 am
Posts: 1185
Location: Zurich, Switzerland
To your first problem: That's caused by "assigned" ids. have a look here:

Code:
http://nhforge.org/doc/nh/en/index.html#example-parentchild-update


Cascaded update needs some additional hints in that case. E.g. a timestamp or a version column. Without that hibernate assumes it has to update that record and therefore is expecting one record and finds 0.

To your second problem: It depends a bit on how you define the fetching in the mapping and the query. And since everything happens in the same session, hibernate will only instantiate every object once, even if its retrieved multiple times.

The best thing to understand what's happening is to enable sql output with "show_sql=true" in the config and play with the mapping and the query.

_________________
--Wolfgang


Top
 Profile  
 
 Post subject:
PostPosted: Fri Feb 06, 2009 12:45 pm 
Newbie

Joined: Wed Feb 04, 2009 5:53 pm
Posts: 5
So I added native id's to all my classes which are mapped to an autoincrementing column and I got the following error:

Code:
WeatherInfo.UnitTest.DALFixture.SensorDAOTest:
NHibernate.AssertionFailure : null id in WeatherInfo.Domain.Zone entry (don't flush the Session after an exception occurs)


Here are the new mappings
Code:
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="WeatherInfo.Domain" namespace="WeatherInfo.Domain">
   <class name="Sensor" table="sensors">

      <id name="Id" column="Id" type="Int32">
         <generator class="assigned"/>
      </id>
      <property column="number" type="Int32" name="Number" not-null="true"/>
      <property column="address" type="String" name="Address" not-null="true" length="256" />
      <property column="enabled" type="Boolean" name="Enabled" not-null="true" />
      <bag name="AssignedZones" table="SensorZoneMap" cascade="save-update" >
         <key column="SensorId"></key>
         <many-to-many class="Zone" column="ZoneId"></many-to-many>
      </bag>
   </class>
</hibernate-mapping>


Code:
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="WeatherInfo.Domain" namespace="WeatherInfo.Domain">
   <class name="Zone" table="zones">
      <id name="Id" column="Id" type="Int32">
         <generator class="native"/>
      </id>
      <property column="Number" type="Int32" name="Num" not-null="true"  />
      <property column="Name" type="String" name="Name" not-null="true" length="256" />
      <property column="enabled" type="Boolean" name="Enabled" not-null="true" />
      <bag name="AssignedSensors" table="SensorZoneMap" lazy="false" inverse="true" >
         <key column="ZoneId"></key>
         <many-to-many class="Sensor" column="SensorId"></many-to-many>
      </bag>
   </class>
</hibernate-mapping>


Any ideas what the problem is here?

Thanks!


Top
 Profile  
 
 Post subject:
PostPosted: Fri Feb 06, 2009 12:50 pm 
Expert
Expert

Joined: Thu Dec 14, 2006 5:57 am
Posts: 1185
Location: Zurich, Switzerland
Quote:
WeatherInfo.UnitTest.DALFixture.SensorDAOTest:
NHibernate.AssertionFailure : null id in WeatherInfo.Domain.Zone entry (don't flush the Session after an exception occurs)


After an exception, the session is invalid and can't be used any more. You have to close it and use a new one. But I can't tell you why you get an exception.

Is it possible that you still have this line in your code ?

testZone.Num = 1;

You mustn't manually assign an id to an automatically generated one.

_________________
--Wolfgang


Top
 Profile  
 
 Post subject:
PostPosted: Fri Feb 06, 2009 12:53 pm 
Newbie

Joined: Wed Feb 04, 2009 5:53 pm
Posts: 5
Duh, I still had the sensor having an Id assigned! Thanks for picking up on that!!


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 6 posts ] 

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.