0
votes

I've spent a couple of days researching this on Google, StackOverflow and reading various blogs on this but to no avail. My question is if a collection is updated within an entity then would this cause NHibernate to update all properties in the entity of the modified collections? In this case I've added a user to a role and once I call session.SaveOrUpdate then 2 updates occur (NHibernate updates user and role) then the INSERT occurs. Is this the default behavior? I've tried to do the following to see if I can get NHibernate to just issue the INSERT statement:

  1. Ran a Ghostbuster test on these entities based on code by Jason Dentler and Fabio Maulo but everything comes back ok and there are no dirty properties.
  2. I made properties nullable that are defined as null in the database.
  3. Set Inverse true on one of the entites.

Any help or insight is much appreciated.

Here are the mapping and class files.

<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" namespace="Custom.NHibernateLib.Model" assembly="Custom.NHibernateLib" xmlns="urn:nhibernate-mapping-2.2">
<class name="Users">
<id name="UserId" type="Int64">
  <generator class="hilo" />
</id>
<property name="ApplicationName" type="String" length="50" />
<property name="Username" type="String" length="15" />
<property name="Email" type="String" length="15" />
<property name="Password" type="String" length="50" />
<property name="PasswordSalt" type="String" length="128" />
<property name="PasswordQuestion" type="String" length="15" />
<property name="PasswordAnswer" type="String" length="50" />
<property name="IsApproved" type="YesNo" />
<property name="LastActivityDate" type="DateTime" />
<property name="LastLoginDate" type="DateTime" />
<property name="LastPasswordChangedDate" type="DateTime" />
<property name="CreationDate" type="DateTime" />
<property name="IsOnline" type="YesNo" />
<property name="IsAnonymous" type="YesNo" />
<property name="IsLockedOut" type="YesNo" />
<property name="LastLockedOutDate" type="DateTime" />
<property name="FailedPasswordAttemptCount" type="Int32" />
<property name="FailedPasswordAttemptWindowStart" type="DateTime" />
<property name="FailedPasswordAnswerAttemptCount" type="Int32" />
<property name="FailedPasswordAnswerAttemptWindowStart" type="DateTime" />
<property name="Comment" type="String" length="4001" />
<bag name="RoleList" table="UserRoles" lazy="true" cascade="save-update, persist" batch-size="10">
  <key column="UserId" not-null="true" />
  <many-to-many class="Roles" foreign-key="FK_Roles_UserRoles_RoleId">
    <column name="RoleId" not-null="true" />
  </many-to-many>
</bag>
<one-to-one name="Profiles" />
</class>
</hibernate-mapping>

<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" namespace="Custom.NHibernateLib.Model" assembly="Custom.NHibernateLib" xmlns="urn:nhibernate-mapping-2.2">
<class name="Roles">
<id name="RoleId" type="Int64">
  <generator class="hilo" />
</id>
<property name="ApplicationName" type="String" length="50" />
<property name="RoleName" type="String" length="50" />
<bag name="UserList" table="UserRoles" lazy="true" inverse="true" cascade="save-update, persist" batch-size="10">
  <key column="RoleId" not-null="true" />
  <many-to-many class="Users" foreign-key="FK_User_UserRoles_UserId">
    <column name="UserId" not-null="true" />
  </many-to-many>
</bag>
</class>
</hibernate-mapping>

Here are the class files:

using System;
using System.Collections.Generic;

namespace Custom.NHibernateLib.Model
{
public class Users : Entity
{
    public Users (){}

    public virtual long UserId { get; set; }
    public virtual string ApplicationName { get; set; }
    public virtual string Username { get; set; }
    public virtual string Email { get; set; }
    public virtual string Password{ get; set; }
    public virtual string PasswordSalt { get; set; }
    public virtual string PasswordQuestion { get; set; }
    public virtual string PasswordAnswer { get; set; }
    public virtual bool? IsApproved { get; set; }
    public virtual DateTime? LastActivityDate { get; set; }
    public virtual DateTime? LastLoginDate { get; set; }
    public virtual DateTime? LastPasswordChangedDate { get; set; }
    public virtual DateTime? CreationDate { get; set; }
    public virtual bool? IsOnline { get; set; }
    public virtual bool? IsAnonymous { get; set; }
    public virtual bool? IsLockedOut { get; set; }
    public virtual DateTime? LastLockedOutDate { get; set; }
    public virtual int? FailedPasswordAttemptCount { get; set; }
    public virtual DateTime? FailedPasswordAttemptWindowStart { get; set; }
    public virtual int? FailedPasswordAnswerAttemptCount { get; set; }
    public virtual DateTime? FailedPasswordAnswerAttemptWindowStart { get; set; }
    public virtual string Comment { get; set; }
    public virtual IList<Roles> RoleList { get; set; }
    public virtual Profiles Profiles { get; set; }
}
}

using System;
using System.Collections.Generic;

namespace Custom.NHibernateLib.Model
{
public class Roles : Entity
{
    public Roles(){}
    public virtual long RoleId { get; set; }
    public virtual string ApplicationName { get; set; }
    public virtual string RoleName { get; set; }
    public virtual IList<Users> UserList { get; set; }
}
}

Adding the user and the role to their respective collections.

usr.RoleList.Add(role);
role.UserList.Add(usr);  

When this is called session.SaveOrUpdate(role) then this occurs in NHibernate.

-- statement #1
UPDATE Users...WHERE  UserId = 32768 
-- statement #2
UPDATE Roles...WHERE  RoleId = 65536 
-- statement #3
INSERT INTO UserRoles...
1
Ok, I think I know what may be causing my particular issue. It may be the way I'm handling the session and transaction. The reason I suspect this is that I used Burrow for NHibernate for session management and re-factored my code to use it. Once I ran my unit test everything came out as expected which was no extra updates before the INSERT. Anyway I will do a bit more reading on Session management as it seems that I'm not to familiar with it as I thought. - Drexter

1 Answers

0
votes

Ok well I can conclude the my issue was caused by the way I was handling the session and commit after the save and update. I was closing the session then recreating it within multiple methods in my custom membership library code. For example, each method I was calling I was wrapping it around a using statement for the session and transaction. I should have known better and not go by my assumptions and just spend the time to RTM. The NHibernate in Action book about session management and using current session context is what guided me. I coded that up to use in my unit test and everything worked fine. Though the book is a bit dated it still had some good basic info.