-->
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.  [ 7 posts ] 
Author Message
 Post subject: Why Does NHibernate Update Database when using HQL
PostPosted: Wed Mar 08, 2006 2:44 pm 
Regular
Regular

Joined: Fri Jan 27, 2006 2:32 pm
Posts: 102
Location: California, USA
I am stumped. In my application, I am trying to change data and save it to the database, but the changes never seem to save.

So, in trying to create a test case, I found that NHibernate is issuing a bunch of update statements for no reason. They are generated when I try to load an object using HQL.

I'm sure this is a mapping issue, because this is the only mapping where I'm using one table -> two classes.

Note: the Search.SearchByHQL is a function of mine, it simply builds an IQuery from the string and returns the IList or object.

Code:
MenuFolder mfTools = (MenuFolder)
    Search.SearchByHQL("from MenuFolder as mf where mf.FolderName = 'Tools'", true);


Here is the log for that statement:

Code:
NHibernate: UPDATE fw_menu SET parent_menu_id = null WHERE parent_menu_id = :p0
:p0 = '5019'
NHibernate: UPDATE fw_menu SET parent_menu_id = null WHERE parent_menu_id = :p0
:p0 = '5016'
NHibernate: UPDATE fw_menu SET parent_menu_id = null WHERE parent_menu_id = :p0
:p0 = '5017'
NHibernate: UPDATE fw_menu SET parent_menu_id = null WHERE parent_menu_id = :p0
:p0 = '5020'
NHibernate: UPDATE fw_menu SET parent_menu_id = null WHERE parent_menu_id = :p0
:p0 = '5021'
NHibernate: UPDATE fw_menu SET parent_menu_id = :p0 WHERE menu_id = :p1
:p0 = '5019'
:p1 = '5020'
NHibernate: UPDATE fw_menu SET parent_menu_id = :p0 WHERE menu_id = :p1
:p0 = '5019'
:p1 = '5021'
NHibernate: UPDATE fw_menu SET parent_menu_id = :p0 WHERE menu_id = :p1
:p0 = '5021'
:p1 = '5031'
NHibernate: UPDATE fw_menu SET parent_menu_id = :p0 WHERE menu_id = :p1
:p0 = '5021'
:p1 = '5030'
NHibernate: UPDATE fw_menu SET parent_menu_id = :p0 WHERE menu_id = :p1
:p0 = '5016'
:p1 = '5019'
NHibernate: UPDATE fw_menu SET parent_menu_id = :p0 WHERE menu_id = :p1
:p0 = '5016'
:p1 = '5018'
NHibernate: UPDATE fw_menu SET parent_menu_id = :p0 WHERE menu_id = :p1
:p0 = '5016'
:p1 = '5017'
NHibernate: UPDATE fw_menu SET parent_menu_id = :p0 WHERE menu_id = :p1
:p0 = '5017'
:p1 = '5023'
NHibernate: UPDATE fw_menu SET parent_menu_id = :p0 WHERE menu_id = :p1
:p0 = '5017'
:p1 = '5022'
NHibernate: UPDATE fw_menu SET parent_menu_id = :p0 WHERE menu_id = :p1
:p0 = '5020'
:p1 = '5029'
NHibernate: UPDATE fw_menu SET parent_menu_id = :p0 WHERE menu_id = :p1
:p0 = '5020'
:p1 = '5027'
NHibernate: UPDATE fw_menu SET parent_menu_id = :p0 WHERE menu_id = :p1
:p0 = '5020'
:p1 = '5024'
NHibernate: UPDATE fw_menu SET parent_menu_id = :p0 WHERE menu_id = :p1
:p0 = '5020'
:p1 = '5025'
NHibernate: UPDATE fw_menu SET parent_menu_id = :p0 WHERE menu_id = :p1
:p0 = '5020'
:p1 = '5028'
NHibernate: UPDATE fw_menu SET parent_menu_id = :p0 WHERE menu_id = :p1
:p0 = '5020'
:p1 = '5026'
NHibernate: select menufolder0_.menu_id as menu_id, menufolder0_.menu_name as me
nu_name, menufolder0_.description as descript4_, menufolder0_.parent_menu_id as
parent_m5_ from fw_menu menufolder0_ where menufolder0_.menu_use_mode='1' and ((
menufolder0_.menu_name='Tools'))


And the mapping file:

Code:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0">
  <class name="ChemRex.Security.Menu, ChemRex.Security" table="fw_menu">
    <id name="MenuID" column="menu_id" type="long">
      <generator class="sequence">
        <param name="sequence">fw_menu_seq</param>
      </generator>
    </id>
    <discriminator column="menu_use_mode" type="String" length="1" />

   
    <subclass name="ChemRex.Security.MenuFolder, ChemRex.Security" discriminator-value="1">
      <property name="FolderName" column="menu_name" type="String" length="30" />
      <property name="Description" column="description" type="String" length="100" />
      <many-to-one name="ParentFolder" class="ChemRex.Security.MenuFolder, ChemRex.Security"
                   column="parent_menu_id" not-null="false" cascade="none" />

      <set name="SubFoldersUntyped" table="fw_menu" inverse="false">
        <key column="parent_menu_id" />
        <one-to-many class="ChemRex.Security.MenuFolder, ChemRex.Security" />
      </set>

      <set name="SubItemsUntyped" table="fw_menu" inverse="false">
        <key column="parent_menu_id" />
        <one-to-many class="ChemRex.Security.MenuItem, ChemRex.Security" />
      </set>
    </subclass>

   
    <subclass name="ChemRex.Security.MenuItem, ChemRex.Security" discriminator-value="2">
      <property name="ItemName" column="menu_name" type="String" length="30" />
      <property name="Description" column="description" type="String" length="100" />
      <many-to-one name="Permission" class="ChemRex.Security.Permission, ChemRex.Security"
                   column="permission_id" not-null="false" cascade="none" />
      <many-to-one name="ParentFolder" class="ChemRex.Security.MenuFolder, ChemRex.Security"
                   column="parent_menu_id" not-null="false" cascade="none" />

      <property name="UserInterfacePageName" column="ui_page_name" type="String" length="100" />
      <property name="UserInterfaceAssembly" column="ui_page_assembly" type="String" length="30" />
      <property name="Mode" column="ui_page_mode" type="ChemRex.Data.MappingTypes.PageModeEnum, ChemRex.Data" />
    </subclass>

  </class>
</hibernate-mapping>


Top
 Profile  
 
 Post subject:
PostPosted: Thu Mar 09, 2006 9:07 am 
Contributor
Contributor

Joined: Wed May 11, 2005 4:59 pm
Posts: 1766
Location: Prague, Czech Republic
NHibernate flushes the session before executing a query, to keep the database up-to-date. In your case it looks that a collection reference belonging to some object was modified, therefore update statements were issued.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Mar 09, 2006 12:28 pm 
Regular
Regular

Joined: Fri Jan 27, 2006 2:32 pm
Posts: 102
Location: California, USA
OK, but I never intentionally changed any data. The code that preceeds that statement is also loading via HQL.

So, what you're saying, is that my first statement is causing changes that are being flushed when my second statement executes.

But why would the first statement cause changes that need to be persisted? And a side note, the update statements put the data back exactly as it is. So, the data prior to those update statements is the same as after the update statements run.

Here is the test code:

Code:
MenuItem miDefinePages = (MenuItem)
    Search.SearchByHQL("from MenuItem as mi where mi.ItemName = 'Define Pages'", true);

Console.WriteLine("Loaded:  " + miDefinePages.ItemName);

MenuFolder mfTools = (MenuFolder)
    Search.SearchByHQL("from MenuFolder as mf where mf.FolderName = 'Tools'", true);

Console.WriteLine("Loaded:  " + mfTools.FolderName);

miDefinePages.ParentFolder = mfTools;


Top
 Profile  
 
 Post subject:
PostPosted: Thu Mar 09, 2006 4:08 pm 
Contributor
Contributor

Joined: Wed May 11, 2005 4:59 pm
Posts: 1766
Location: Prague, Czech Republic
Do you do anything non-trivial in getters/setters of MenuItem and MenuFolder? Especially the accessors of collection and reference properties? What do these classes look like?

Also, if you enable debug logging, you should see what fields NHibernate considers to have changed.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Mar 09, 2006 5:08 pm 
Regular
Regular

Joined: Fri Jan 27, 2006 2:32 pm
Posts: 102
Location: California, USA
sergey wrote:
Do you do anything non-trivial in getters/setters of MenuItem and MenuFolder? Especially the accessors of collection and reference properties? What do these classes look like?


Yes, I am doing something "special"...

I'm using .Net 2.0, so I have stongly typed List<> collections, and in order to get NHibernate to use them, I provide an untyped property that I use in my mappings. It looks like this:

Code:
        private List<MenuFolder> _subFolders = null;
        private List<MenuItem> _menuItems = null;

        /// <summary>
        /// Untyped collection for use with NHibernate.
        /// </summary>
        protected Iesi.Collections.ISet SubFoldersUntyped
        {
            get
            {
                return new Iesi.Collections.HybridSet(_subFolders);
            }
            set
            {
                _subFolders.Clear();
                foreach (object o in value)
                {
                    if (o is MenuFolder)
                    {
                        _subFolders.Add((MenuFolder)o);
                    }
                }

            }
        }


Top
 Profile  
 
 Post subject:
PostPosted: Fri Mar 10, 2006 6:00 am 
Contributor
Contributor

Joined: Wed May 11, 2005 4:59 pm
Posts: 1766
Location: Prague, Czech Republic
NHibernate tracks collections by reference, so to avoid this problem you should return in the getter the same collection reference that was passed to the setter.

Or you can of course set session.FlushMode to FlushMode.Never or FlushMode.Commit to disable automatic flushing before queries, but then you risk getting incorrect data from a query.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Mar 10, 2006 12:55 pm 
Regular
Regular

Joined: Fri Jan 27, 2006 2:32 pm
Posts: 102
Location: California, USA
Thanks for your help, I changed my collections to ISet and exposed them and NHibernate stopped trying to issue SQL update statements.

So, I guess my classes need to have private ISet collections. I'll look to see if I can expose them as List<> collections, but if not, I guess I'll just have to wait for NHibernate to support generics.

Thanks again,
Brian


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 7 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.