-->
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: Dazed & Confused about bidirectional mapping tags!
PostPosted: Tue Aug 14, 2007 2:17 pm 
Newbie

Joined: Fri Jul 20, 2007 7:45 pm
Posts: 12
Location: Amgen Corp
I’m pretty confused about the mapping tag definitions for a bidirectional one-to-many mapping.

Say I have want a classic bi-directional one-to-many association between a claimant (the parent class) and a list of pets that belong to the claimant. I have two database tables: Claimant, and Pet. The Claimant table has one column: claimant_id. The Pet table has two columns: pet_id, and pet_claimant_id. The pet_claimant_id is a foreign key that refers to a row in the Claimant table.

Here are my classes:

public class Claimant
{
private Int32 claimant_id;
private ISet claimant_pets;
public Claimant()
{ claimant_pets = new ListSet(); }
public virtual Int32 Claimant_id
{
get { return claimant_id; }
set { claimant_id = value; }
}
public virtual ISet Claimant_pets
{
get { return claimant_pets; }
set { claimant_pets = value; }
}
}
public class Pet
{
private Int32 pet_id;
private Int32 pet_claimant_id;
public virtual Int32 Pet_id
{
get { return pet_id; }
set { pet_id = value; }
}
public virtual Int32 Pet_claimant_id
{
get { return pet_claimant_id; }
set { pet_claimant_id = value; }
}
}

Notice that a Claimant has an ISet named Claimant_pets.

I have the following map:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
namespace="RentAssist" assembly="RentAssist">
<class name="RentAssist.Claimant" table="Claimant">
<!-- The Claimant_id is the primary key. It's saved in a table. -->
<id name="Claimant_id" type="Int32" column="claimant_id">
<generator class="hilo">
<param name="table">claimant_hi_value</param>
<param name="column">next_value</param>
<param name="max_lo">0</param>
</generator>
</id>
<set name="Claimant_pets" cascade="all-delete-orphan" lazy="true">
<key column="pet_claimant_id"/>
<one-to-many class="Pet"/>
</set>
</class>
<class name="RentAssist.Pet" table="Pet">
<!-- The Pet_id is the primary key. It's saved in a table. -->
<id name="Pet_id" type="Int32" column="pet_id">
<generator class="hilo">
<param name="table">pet_hi_value</param>
<param name="column">next_value</param>
<param name="max_lo">0</param>
</generator>
</id>
<!-- A Pet has a claimant that owns the pet -->
<property name="Pet_claimant_id" type="Int32" column="pet_claimant_id"/>
<many-to-one name="Pet_claimant_id" class="RentAssist.Claimant" column="claimant_id"/>
</class>
</hibernate-mapping>

This simple example is not working, and I think I’ve got the tags wrong. Here are my questions about the tags.

1) Should the <key column= /> in <set /> refer to the name of the foreign key column in the child class?

2) Should the column in the child class with the foreign key be defined as a property: <property name="Pet_claimant_id" type="Int32" column="pet_claimant_id"/>

3) In the <many-to-one /> tag in the child class what are name, class, and column referring to? If I put a name from the parent class in as the name (e.g. Claimant_id) Nhibernate complains that there is no such property in the child class. Should the class name be the parent class (I’m guessing it has to be)? And finally what goes in the column? Should it be the foreign key column of the child or the primary key of the parent?

WHen I run the example as-is, I get an “Unknown Entity class:System.Int32” exception when cascade goes to save the children.

_________________
Fred Stann
Solutions Architect


Top
 Profile  
 
 Post subject:
PostPosted: Tue Aug 14, 2007 5:22 pm 
Hibernate Team
Hibernate Team

Joined: Tue Jun 13, 2006 11:29 pm
Posts: 315
Location: Calgary, Alberta, Canada
Change this
Code:
   private Int32 pet_claimant_id;
   public virtual Int32 Pet_claimant_id
   {
       get { return pet_claimant_id; }
       set { pet_claimant_id = value; }
   }

to
Code:
   private Claimant pet_claimant;
   public virtual Claimant Pet_claimant
   {
       get { return pet_claimant; }
       set { pet_claimant = value; }
   }

Remove this:
Code:
<property name="Pet_claimant_id" type="Int32" column="pet_claimant_id"/>

And change this
Code:
<many-to-one name="Pet_claimant_id" class="RentAssist.Claimant" column="claimant_id"/>

to
Code:
<many-to-one name="Pet_claimant" class="RentAssist.Claimant" column="claimant_id"/>


I suggest you get the many-to-one working before making it bidirectional. I also suggest you study the example in the docs here:
http://www.hibernate.org/hib_docs/nhibe ... asses-poco

_________________
Karl Chu


Top
 Profile  
 
 Post subject:
PostPosted: Tue Aug 14, 2007 6:28 pm 
Newbie

Joined: Fri Jul 20, 2007 7:45 pm
Posts: 12
Location: Amgen Corp
Hi Karlchu,

I made the changes that you suggested, and I got an error that NHibernate could not insert the Pets because pet had no column named "claimant_id."

So I thought maybe that should be "pet_claimant_id." When I tried that I got an error that Nhibernate could not insert the pets because their "pet_claimant_id" is null.

So I decided to delete the many to one from pet, and just try the one-to-many, which I worked earlier.

I did not add back the Pet_claimant_id property.

I'm getting the same error that it can't insert pets with null "pet_claimant_id".

I'll keep trying, and looking at the docs, but if you have any more ideas let me know.

I guess you are telling me that in the Pet object, there is a reference to the parent object, and not the Primary key.

Thanks,
Fred

_________________
Fred Stann
Solutions Architect


Top
 Profile  
 
 Post subject:
PostPosted: Tue Aug 14, 2007 10:55 pm 
Expert
Expert

Joined: Fri May 13, 2005 11:13 am
Posts: 292
Location: Rochester, NY
Two more: add inverse='true' to your <set>, and make sure that you set the claimant property on the pet (so that the foreign key will be set) and add the pet to the claimant's pet collection (so that the cascading will work).


Top
 Profile  
 
 Post subject:
PostPosted: Tue Aug 14, 2007 11:50 pm 
Hibernate Team
Hibernate Team

Joined: Tue Jun 13, 2006 11:29 pm
Posts: 315
Location: Calgary, Alberta, Canada
Fred, assuming that it is still a unidirectional mapping, your null exception is explained by the docs:
Quote:
Very Important Note: If the <key> column of a <one-to-many> association is declared NOT NULL, NHibernate may cause constraint violations when it creates or updates the association. To prevent this problem, you must use a bidirectional association with the many valued end (the set or bag) marked as inverse="true". See the discussion of bidirectional associations later in this chapter.

Ref: http://www.hibernate.org/hib_docs/nhibe ... -onetomany

If you are still learning NHibernate, I would still suggest getting the mapping to work in one direction before making it bidirectional. To fix the problem described above, just remove the NOT NULL constraint temporarily (if you have control of the database).

Also, what you said below is correct.
Quote:
I guess you are telling me that in the Pet object, there is a reference to the parent object, and not the Primary key.

_________________
Karl Chu


Top
 Profile  
 
 Post subject:
PostPosted: Wed Aug 15, 2007 2:01 pm 
Newbie

Joined: Fri Jul 20, 2007 7:45 pm
Posts: 12
Location: Amgen Corp
Wow - it works! (even with referential integrity turned on in the DB)

Karlchu and Marcal, thank you so much for your assistance.

In retrospect, my biggest problem was thinking that a foreign key needed to be present in the child object as a database foreign key, rather than an object reference.

Here are my revised classes:
public class Claimant
{
private Int32 claimant_id;
// lots of other variables
private ISet claimant_pets;
// the public virtual getters and setters go here
}

public class Pet
{
private Int32 pet_id;
// lots of other variables
private Claimant pet_claimant;
// the public virtual getters and setters go here
}

Here are my revised mapping elements:

<set name="Claimant_pets" cascade="all-delete-orphan" lazy="true" inverse="true">
<key column="pet_claimant_id"/>
<one-to-many class="Pet"/>
</set>

<many-to-one name="Pet_claimant" class="RentAssist.Claimant" column="pet_claimant_id"/>

Here’s my revised code:

somePet.Pet_claimant = someClaimant;
someClaimant.Claimant_pets.Add(somePet);
ISession session = NHibernateHelper.GetCurrentSession();
ITransaction tx = session.BeginTransaction();
session.Save(someClaimant);
tx.Commit();
NHibernateHelper.CloseSession();

_________________
Fred Stann
Solutions Architect


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.