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.  [ 9 posts ] 
Author Message
 Post subject: Parent/Child question.
PostPosted: Sun Jun 22, 2008 8:18 am 
Newbie

Joined: Sun Jun 22, 2008 7:34 am
Posts: 5
First off I have read chapter 17 over and over and I have got it to work several times (for instance in the classes below I have successfully mapped the Visitors held in the Visit). However, I have run into a stumbling block. I have the following classes:

Code:
    public class Visit
    {
        public int ID { get; set; }
        public IList<Visitor> Visitors { get; set; }
        public Requestor Requestor { get; set; }
        public DateTime StartDate { get; set; }
        public DateTime EndDate { get; set; }
    }

    public class Requestor
    {
        public String Name { get; set; }
        public IList<Visit> Visits { get; set; }
    }

    public class Visitor
    {
        // Some properties
    }


Code:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0">
  <class name="Visit, Examples.Visit" table="visit">
    <id name="ID" column="pk_id" type="int">
      <generator class="native" />
    </id>
    <many-to-one name="Requestor" column="requestor_id" not-null="false" />
  </class>

  <class name="Requestor, Examples.Requestor" table="requestor">
    <id name="ID" column="pk_id" type="int">
      <generator class="native" />
    </id>
    <set name="Visits" table="visit" inverse="true">
      <key column="requestor_id" />
      <one-to-many class="Visit" />
    </set>
  </class>
</hibernate-mapping>


Code:
The visit table has a foreign_key linking it to the requestor table.

CREATE TABLE visit (
pk_id int NOT NULL,
Name nvarchar(40) default NOT NULL,
requestor_id int NULL
PRIMARY KEY  (pk_id)
)

CREATE TABLE requestor (
pk_id int NOT NULL,
)


Visit v = new Visit();
Requestor r = new Requestor();
v.AddRequestor(r);
session.Save(r);
session.Flush();


I am still getting up the Update statement called to update the visit table with the requestor pk_id. However, this throws an intergrityConstraint indicating the foreign_key linking the visit table to the requestor table is violated.

I looked at the log file and traced through and it shows the insert statement for the requestor table but it doesn't show the requestor pk_id.

Any thoughts would be appreciated. [/code]

_________________
Jamie


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jun 23, 2008 5:27 am 
Expert
Expert

Joined: Thu Dec 14, 2006 5:57 am
Posts: 1185
Location: Zurich, Switzerland
The only thing I can see, that's different from the documentation and the mappings that I use, is the missing cascade on the collection. Try to add cascade="all" to the set mapping and see if that helps.

_________________
--Wolfgang


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jun 23, 2008 5:35 pm 
Newbie

Joined: Sun Jun 22, 2008 7:34 am
Posts: 5
wolli wrote:
The only thing I can see, that's different from the documentation and the mappings that I use, is the missing cascade on the collection. Try to add cascade="all" to the set mapping and see if that helps.


This was just a typo in my post. I had the cascade in the mapping.

After digging a little deeper I have figured out exactly what is happening but I am unsure how to fix it.

My problem is with mapping an inheritance Child to a Parent. Looking at the log files I see that the Parent/Child mapping as described in Chapter 17 is working properly. I am getting the two insert statements and no update statement now.

I have the following classes:

Code:
    public class Visit
    {
        public int ID { get; set; }
        public IList<Visitor> Visitors { get; set; }
        public Requestor Requestor { get; set; }
        public DateTime StartDate { get; set; }
        public DateTime EndDate { get; set; }
    }

    public class Person
    {
        public String Name { get; set; }
    }

    public class Requestor : Person
    {
        public String Section { get; set; }
        public IList<Visit> Visits { get; set; }
    }

    public class Visitor : Person
    {
        // Some properties
    }


They are mapped as follows:


Code:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0">
  <class name="Visit, Examples.Visit" table="visit">
    <id name="ID" column="pk_id" type="int">
      <generator class="native" />
    </id>
    <many-to-one name="Requestor" column="requestor_id" not-null="false" />
  </class>

  <class name="Person, Examples.Person" table="person">
    <id name="ID" column="pk_id" type="int">
      <generator class="native" />
    </id>
      <property name="Name" type="String">
        <column name="name" length="50" sql-type="varchar" not-null="false" />
      </property>
      <joined-subclass name="Requestor, Examples.Requestor" table="requestor" lazy="false">
        <key column="fk_person_id" />
        <bag name="Visits" table="visit" cascade="all-delete-orphan" inverse="true" lazy="true">
          <key column="fk_requestor_id" />
          <one-to-many class="Visit" />
        </bag>
        <property name="Section" type="String" not-null="true">
          <column name="section" length="50" sql-type="varchar" not-null="true" />
        </property>
      </joined-subclass>
  </class>
</hibernate-mapping>


Code:
CREATE TABLE visit (
pk_id int NOT NULL,
Name nvarchar(40) default NOT NULL,
fk_requestor_id int NULL
PRIMARY KEY  (pk_id)
)

CREATE TABLE person (
name varchar(50) NOT NULL,
)

CREATE TABLE requestor (
pk_id int NOT NULL,
fk_person_id int NOT NULL
)


When I execute the save on Requestor I get the following inserts based on the log file:

INSERT INTO person (Name) VALUES (@p0)

after the above statement I see a log statement
Select SCOPE_IDENTITY();
returning '40' as column:
NHibernate.Persister.Entity.AbstractEntityPersister [(null)] - Nativley generate identity: 40

This is the pk_id generate for the newly inserted person.

and then I see the following insert:

INSERT INTO requestor (fk_person_id) VALUES (@p0)

where @p0 is the identity previously Selected of 40.

Finally, I see

INSERT INTO visit (Name, fk_requestor_id) VALUES (@p0, @p1)

where @p0 is the value in the Visit.Name Property and
@p1 is 40.

This final 40 is where my problem exists. It is trying to insert the visit using the person pk_id and not the requestor pk_id. In fact there is no Select SCOPE_IDENTITY(); called on the requestor table after the insert of the requestor data.

Thanks ahead of time for any help.

_________________
Jamie


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jun 24, 2008 2:21 am 
Expert
Expert

Joined: Thu Dec 14, 2006 5:57 am
Posts: 1185
Location: Zurich, Switzerland
Quote:
This final 40 is where my problem exists. It is trying to insert the visit using the person pk_id and not the requestor pk_id. In fact there is no Select SCOPE_IDENTITY(); called on the requestor table after the insert of the requestor data.


As far as I understood the joind-subclass mapping this is exactly what I would expect. The two entities are linked with the same id.

In your posting, you have pk_id in requestor and not in person and what about visitor ? Can you also post the visitor part ?

_________________
--Wolfgang


Top
 Profile  
 
 Post subject: Parent/Child where Parent is an Inheritance Mapping
PostPosted: Tue Jun 24, 2008 3:03 pm 
Newbie

Joined: Sun Jun 22, 2008 7:34 am
Posts: 5
wolli wrote:
Quote:
This final 40 is where my problem exists. It is trying to insert the visit using the person pk_id and not the requestor pk_id. In fact there is no Select SCOPE_IDENTITY(); called on the requestor table after the insert of the requestor data.


As far as I understood the joind-subclass mapping this is exactly what I would expect. The two entities are linked with the same id.

In your posting, you have pk_id in requestor and not in person and what about visitor ? Can you also post the visitor part ?


The pk_id is in both requestor and person. I even did a test to ensure they were both being set by removing the link between visit and requestor in the mappings and then saving the requestor and the visit in my DAO. In this case everything inserts correctly except I don't get the pk_id of the requestor inserted/updated into the fk_requestor_id of my visit. I do however get different ID's in the person and requestor table. So, I would have a person with an ID of 40 and the requestor would have ID 6 with a fk_person_id set to 40 which is exactly what I want. The only thing missing is the linking of the requestor (6) to the visit via the fk_requestor_id in visit.

I suppose I could get this to work by updating the visit using the pk_id of the requestor that is set when it is inserted, something like this in my save method:
Code:
HibernateTemplate.Save(visit.Requestor);
HibernateTemplate.Save(visit);
visit.SetRequestorID(Requestor.ID);
HibernateTemplate.Update(visit);


But this would mean I would be manually responsible for handling the link which doesn't make much sense to me?

I have posted the visitor mapping below within the Person mapping (The added space around it is just to make it stick out and easier to read). This one is different then the requestor however. Since the Visitor holds the visit_id as fk_visit_id. It is the opposite of requestor and in fact I have it mapped pretty much the same except for the bag and the many-to-one are in opposite direction.


Code:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0">
  <class name="Visit, Examples.Visit" table="visit">
    <id name="ID" column="pk_id" type="int">
      <generator class="native" />
    </id>
    <many-to-one name="Requestor" column="requestor_id" not-null="false" />
  </class>

  <class name="Person, Examples.Person" table="person">
    <id name="ID" column="pk_id" type="int">
      <generator class="native" />
    </id>
      <property name="Name" type="String">
        <column name="name" length="50" sql-type="varchar" not-null="false" />
      </property>

      <joined-subclass name="Visitor, Examples.Visitor" table="visitor" lazy="false">
        <key column="fk_person_id" />
        <many-to-one name="Visit" column="fk_visit_id" not-null="true" />
</joined-subclass>

      <joined-subclass name="Requestor, Examples.Requestor" table="requestor" lazy="false">
        <key column="fk_person_id" />
        <bag name="Visits" table="visit" cascade="all-delete-orphan" inverse="true" lazy="true">
          <key column="fk_requestor_id" />
          <one-to-many class="Visit" />
        </bag>
        <property name="Section" type="String" not-null="true">
          <column name="section" length="50" sql-type="varchar" not-null="true" />
        </property>
      </joined-subclass>
  </class>
</hibernate-mapping>


Code:
CREATE TABLE visit (
pk_id int NOT NULL,
Name nvarchar(40) default NOT NULL,
fk_requestor_id int NULL
PRIMARY KEY  (pk_id)
)

CREATE TABLE person (
pk_id int NOT NULL,
name varchar(50) NOT NULL,
)

CREATE TABLE requestor (
pk_id int NOT NULL,
fk_person_id int NOT NULL
)

CREATE TABLE visitor (
pk_id int NOT NULL,
fk_person_id int NOT NULL
)

_________________
Jamie


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jun 24, 2008 3:56 pm 
Expert
Expert

Joined: Thu Dec 14, 2006 5:57 am
Posts: 1185
Location: Zurich, Switzerland
I'm not sure what's the cause of your problem. But I think one thing is strange here ... where do the pk_id values for requestor and visitor come from. With a joined-subclass mapping you don't need them.
You can either use "pk_id" as key column for the joined subclass and remove the fk_person_id column from both tables or vice versa, but you don't need both.

_________________
--Wolfgang


Top
 Profile  
 
 Post subject: Parent/Child Mapping
PostPosted: Tue Jun 24, 2008 4:43 pm 
Newbie

Joined: Sun Jun 22, 2008 7:34 am
Posts: 5
wolli wrote:
I'm not sure what's the cause of your problem. But I think one thing is strange here ... where do the pk_id values for requestor and visitor come from. With a joined-subclass mapping you don't need them.
You can either use "pk_id" as key column for the joined subclass and remove the fk_person_id column from both tables or vice versa, but you don't need both.


Ok, this is starting to make sense now, I think. I can use the pk_id from person as the same id for visitor and requestor. Or I can remove the pk_id from requestor and visitor and use the fk_person_id in both.

So to me it sounds more like my schema in the database then my Nhibernate mappings.

_________________
Jamie


Top
 Profile  
 
 Post subject: Re: Parent/Child Mapping
PostPosted: Tue Jun 24, 2008 8:15 pm 
Newbie

Joined: Sun Jun 22, 2008 7:34 am
Posts: 5
pnddgg972 wrote:
wolli wrote:
I'm not sure what's the cause of your problem. But I think one thing is strange here ... where do the pk_id values for requestor and visitor come from. With a joined-subclass mapping you don't need them.
You can either use "pk_id" as key column for the joined subclass and remove the fk_person_id column from both tables or vice versa, but you don't need both.


Ok, this is starting to make sense now, I think. I can use the pk_id from person as the same id for visitor and requestor. Or I can remove the pk_id from requestor and visitor and use the fk_person_id in both.

So to me it sounds more like my schema in the database then my Nhibernate mappings.


This was exactly the problem. I removed the pk_id from the visitor and requestor and make the fk_person_id both a primary and foreign key and it worked. Thank you so much for your help.

Now I am on to my next problem involving the collection of visits being updated while processing the cascades from the requestor. This is causing an InvalidOperationException in the enumerator.

_________________
Jamie


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jun 25, 2008 1:59 am 
Expert
Expert

Joined: Thu Dec 14, 2006 5:57 am
Posts: 1185
Location: Zurich, Switzerland
When does that happen ? Btw.

Code:
<many-to-one name="Requestor" column="requestor_id" not-null="false" />


Shouldn't that be not-null="true" ? Afaik that has an influence on the order of generated inserts/updates.

_________________
--Wolfgang


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