-->
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.  [ 2 posts ] 
Author Message
 Post subject: Cascade insert not working as expected
PostPosted: Fri Oct 19, 2007 10:34 am 
Newbie

Joined: Fri Oct 19, 2007 7:23 am
Posts: 2
Hi,

I am using the NHibernate 1.2 GA. The development Env is MS Visual Studio 2005 and Database is MS SQL 2005.

First I will explain what is the object structure and what I am trying to do.

Tables and Classes
I have three tables/classes namely Member, MemberGroup and Member_MemberGroup.

Member table store the data for members.

MemberGroup table holds the groups available in system like "Admin", "Normal", "Guest". MemberGroup table is sort of Master table in which the data is one time inserted during application setup.

The Member_MemberGroup table is a link table which associates Member and MemberGroup i.e. a Member could be in multiple groups say Admin as well as Normal.


The relationship between Member and MemberGroup table is many-to-many.

What I am trying to do.

My requirement is that whenever a Member record is inserted into the database, the record(s) in the link table should also get inserted if the
data entry user has specified the MemberGroups as well.

Mapping files

Member

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class name="NHibernateLearning.Domain.Member, NHibernateLearning" table="Member">
<id name ="MemberId" column="MemberId" type="Int32" unsaved-value="0">
<generator class="native"></generator>
</id>
<property name="FirstName" column="FirstName"/>
<property name="LastName" column="LastName"/>
<property name="DOB" column="DOB"/>
<property name="Gender" column="Gender"/>
<property name="Address" column="Address"/>
<property name="Email" column="Email"/>
<property name="Password" column="Password"/>
<bag name="Groups" table="[PPMISA].[dbo].Member_MemberGroup" lazy="false" cascade="all">
<key column="MemberId"></key>
<many-to-many class="NHibernateLearning.Domain.MemberGroup, NHibernateLearning" column="MemberGroupId"></many-to-many>
</bag>
</class>
</hibernate-mapping>

MemberGroup

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class name="NHibernateLearning.Domain.MemberGroup, NHibernateLearning" table="[PPMISA].[dbo].MemberGroup">
<id name ="MemberGroupId" column="MemberGroupId" type="Int32" unsaved-value="0">
<generator class="native"></generator>
</id>
<property name="Code" column="Code"/>
<property name="DisplayText" column="DisplayText"/>
<bag name="Members" table="[PPMISA].[dbo].Member_MemberGroup" lazy="false" cascade="all">
<key column="MemberGroupId"></key>
<many-to-many class="NHibernateLearning.Domain.Member, NHibernateLearning" column="MemberId"></many-to-many>
</bag>
</class>
</hibernate-mapping>


public class Member
{
private int m_MemberId;
private string m_FirstName;
private string m_LastName;
private DateTime m_DOB;
private char m_Gender;
private string m_Address;
private string m_Email;
private string m_Password;
private IList<MemberGroup> m_Groups = new List<MemberGroup>();

public virtual int MemberId { get { return m_MemberId; } set { m_MemberId = value; } }
public virtual string FirstName { get { return m_FirstName; } set { m_FirstName = value; } }
public virtual string LastName { get { return m_LastName; } set { m_LastName = value; } }
public virtual DateTime DOB { get { return m_DOB; } set { m_DOB = value; } }
public virtual char Gender { get { return m_Gender; } set { m_Gender = value; } }
public virtual string Address { get { return m_Address; } set { m_Address = value; } }
public virtual string Email { get { return m_Email; } set { m_Email = value; } }
public virtual string Password { get { return m_Password; } set { m_Password = value; } }
public virtual IList<MemberGroup> Groups { get { return m_Groups; } set { m_Groups = value; } }

}


public class MemberGroup
{
private int m_MemberGroupId;
private string m_Code;
private string m_DisplayText;
private IList<Member> m_Members = new List<Member>();

public virtual int MemberGroupId { get { return m_MemberGroupId; } set { m_MemberGroupId = value; } }
public virtual string Code { get { return m_Code; } set { m_Code = value; } }
public virtual string DisplayText { get { return m_DisplayText; } set { m_DisplayText = value; } }
public virtual IList<Member> Members { get { return m_Members; } set { m_Members = value; } }
}


Code Snippet where I prepare the Member class for data insert

Member newMemberData = new Member();
newMemberData.FirstName = txtFName.Text;
newMemberData.LastName = txtLName.Text;
newMemberData.DOB = Convert.ToDateTime(txtDOB.Text);
newMemberData.Address = txtAddress.Text;
newMemberData.Email = txtEmail.Text;
newMemberData.Password = txtPassword.Text;

MemberGroup normalUserGroup = new MemberGroup();
normalUserGroup.MemberGroupId = 2; //2 stands for "Normal".
newMemberData.Groups.Add(normalUserGroup);



Code snippet for actual data insert operation

void IMemberManager.AddNew(Member newMemberData)
{
ISession session = SessionFactory.OpenSession();
ITransaction tx = session.BeginTransaction();
try
{
session.Save(newMemberData);
tx.Commit();
session.Close();
}
catch (Exception exp)
{
tx.Rollback();
session.Close();
throw; //Best would be throw a custom exception stating the exact reason why database insert is a failure
}
}

The Exception I am getting

[NHibernate.ADOException] = {"could not update: [NHibernateLearning.Domain.MemberGroup#2][SQL: UPDATE [PPMISA].[dbo].MemberGroup SET Code = ?, DisplayText = ? WHERE MemberGroupId = ?]"}
and the inner exception
InnerException = {"Cannot insert the value NULL into column 'Code', table 'PPMISA.dbo.MemberGroup'; column does not allow nulls. UPDATE fails.\r\nThe statement has been terminated."}


Full Stack Trace

exp.StackTrace " at NHibernate.Persister.Entity.AbstractEntityPersister.Update(Object id, Object[] fields, Object[] oldFields, Boolean[] includeProperty, Int32 j, Object oldVersion, Object obj, SqlCommandInfo sql, ISessionImplementor session)\r\n at NHibernate.Persister.Entity.AbstractEntityPersister.Update(Object id, Object[] fields, Int32[] dirtyFields, Boolean hasDirtyCollection, Object[] oldFields, Object oldVersion, Object obj, ISessionImplementor session)\r\n at NHibernate.Impl.ScheduledUpdate.Execute()\r\n at NHibernate.Impl.SessionImpl.Execute(IExecutable executable)\r\n at NHibernate.Impl.SessionImpl.ExecuteAll(IList list)\r\n at NHibernate.Impl.SessionImpl.Execute()\r\n at NHibernate.Impl.SessionImpl.Flush()\r\n at NHibernate.Transaction.AdoTransaction.Commit()\r\n at NHibernateLearning.Facade.MemberManager.NHibernateLearning.Facade.IMemberManager.AddNew(Member newMemberData) in

Query

If you closely see both the above exceptions then you can figure out that, the NHibernate is trying to update data into MemberGroup table, where as the link between Member and MemberGroup is via Member_MemberGroup link table which means whenever I insert an item into the Groups collection of Member class then a new record should be inserted into the link table not in the master table (i.e. MemberGroup table)

Is my assumption wrong?

Though I am novice to NHibernate tool but as per my understanding the Object Model in your application is mapped to database schema via mapping files and if we have indicated in mapping files that what is relationship between two Objects then NHibernate should be able to deduce the appropriate database logic.

What is surprising is that the same mappings files are working file if I read data, i.e. if I issue a Read query then NHibernate correctly returns the Member and the associated MemberGroups in Group collection, but while inserting it is trying to put data in MemberGroup whereas it should go into Link table.


Am I doing anything wrong, I mean the cascade="all" option which I have set in mapping files shouldn't be used or there is another way to manage the cascaded inserts.

Please advise.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Oct 22, 2007 7:30 am 
Newbie

Joined: Fri Oct 19, 2007 7:23 am
Posts: 2
Hi,

After replacing the following code with some changes I was able to get the cascade insert working.

Old code
See the Code Snippet where I prepare the Member class for data insert heading in original post.
MemberGroup normalUserGroup = new MemberGroup();
normalUserGroup.MemberGroupId = 2; //2 stands for "Normal".
newMemberData.Groups.Add(normalUserGroup);

Replaced Code
IMemberGroupManager memberGrpMgr = MemberGroupManager.GetInstance();
MemberGroup normalUserGroup = memberGrpMgr.Get("NORMAL");
newMemberData.Groups.Add(normalUserGroup);


Basically the changes make sure that there is data in every field of the MemberGroup class/table.

What seems to be happening is that if you want to have your link table inserted then the NHibernate also issues udpate query for the Master table (i.e. MemberGroup table).

Though this doesn't seems the right way to have the cascade insert work but I guess this is how it works.


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