-->
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.  [ 14 posts ] 
Author Message
 Post subject: Inheritance joined-subclass foreign-key/identity column same
PostPosted: Thu May 15, 2008 11:20 pm 
Newbie

Joined: Thu May 15, 2008 10:51 pm
Posts: 8
I've tried playing with this extensively. I've tried searching google and can't seem to find anything pointing how to do this.

Scenario is i have a class A with a ID, class B extends class A... simple inheritance. In the database class A is a seperate table as class B... A has a auto generated ID... B has a foreign key value ID pointing to A

If i remove the joined-subclass and make Character a property of Player instead of it being inherited i have no problems at all and i can get it to work just fine. I decided i didn't want that design and i want player to inherit character... but character will be inherited from other things as well like NPC class etc...

EDIT: I wanted to point out that if i added another field to the Player table and call it say ID2 and marked it as a identity column, then change the xml to reflect it, i still get the same dupe/key error. So it doesn't have anything to do with both xml files containing a ID field...

heres the code illustrating it.

Hibernate version: 2.0.0.Alpha1

Mapping documents:

Character.hbm.xml
Code:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                  assembly="Convergence.Libraries.Core"
                  namespace="Convergence.Libraries.Core.Entities">

  <class name="Character" table="Character">
    <id name="ID" column="ID" type="Int64">     
      <generator class="identity"/>
    </id>
   
    <property name="Name" type="String" length="50" column="Name"/>
    <property name="Health" type="Int32" column="Health"/>
  </class>
 
</hibernate-mapping>


Player.hbm.xml
Code:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                  assembly="Convergence.Libraries.Core"
                  namespace="Convergence.Libraries.Core.Entities">

  <class name="Player" table="Player" lazy="false">
    <id name="ID" column="ID" type="Int64">
      <generator class="assigned"/>
    </id>

    <property  name="Password" type="String" length="50" column="Password" not-null="true" />

    <joined-subclass name="Character" table="Character">
      <key column="ID"/>
    </joined-subclass>
  </class>
</hibernate-mapping>


Character.cs
Code:
namespace Convergence.Libraries.Core.Entities
{
    public class Character
    {
        public Character() { }
        public Character(string name)
        {
            Name = name;
        }

        public virtual long ID { get; private set; }
        public virtual string Name { get; private set; }
        public virtual string Health { get; private set; }

    }
}


Player.cs
Code:
using NHibernate;

namespace Convergence.Libraries.Core.Entities
{
    public class Player : Character
    {
        public virtual string Password { get; set; }

        public static Player GetById(long id)
        {
            using (ISession session = Database.GetSession())
                return session.Load<Player>(id);
        }

        public static void Save(Player p)
        {
            using (ISession session = Database.GetSession())
                Save(p, session);
        }

        public static void Save(Player p, ISession session)
        {
            session.Save(p);
        }
    }
}


Full stack trace of any exception that occurs:
Failure line
Code:
cfg.AddAssembly("Convergence.Libraries.Core"); //Could not compile the mapping document: Convergence.Libraries.Core.Entities.Character.hbm.xml


Error (Inner Exception)
Code:
NHibernate.DuplicateMappingException: Duplicate class/entity mapping Convergence.Libraries.Core.Entities.Character
   at NHibernate.Cfg.Mappings.AddClass(PersistentClass persistentClass)
   at NHibernate.Cfg.XmlHbmBinding.RootClassBinder.Bind(XmlNode node, HbmClass classSchema)
   at NHibernate.Cfg.XmlHbmBinding.MappingRootBinder.AddRootClasses(XmlNode parentNode)
   at NHibernate.Cfg.XmlHbmBinding.MappingRootBinder.Bind(XmlNode node)
   at NHibernate.Cfg.Configuration.AddValidatedDocument(NamedXmlDocument doc)


Stack Trace
Code:
   at NHibernate.Cfg.Configuration.LogAndThrow(Exception exception)
   at NHibernate.Cfg.Configuration.AddValidatedDocument(NamedXmlDocument doc)
   at NHibernate.Cfg.Configuration.ProcessMappingsQueue()
   at NHibernate.Cfg.Configuration.AddDocumentThroughQueue(NamedXmlDocument document)
   at NHibernate.Cfg.Configuration.AddXmlReader(XmlReader hbmReader, String name)
   at NHibernate.Cfg.Configuration.AddInputStream(Stream xmlInputStream, String name)
   at NHibernate.Cfg.Configuration.AddResource(String path, Assembly assembly)
   at NHibernate.Cfg.Configuration.AddAssembly(Assembly assembly)
   at NHibernate.Cfg.Configuration.AddAssembly(String assemblyName)
   at Convergence.Libraries.Core.Database.Initialize() in D:\\source\\.NET\\Convergence\\Libraries\\Convergence.Libraries.Framework\\Database.cs:line 30

Name and version of the database you are using: MSSQL 2005


Top
 Profile  
 
 Post subject:
PostPosted: Fri May 16, 2008 2:54 am 
Expert
Expert

Joined: Thu Dec 14, 2006 5:57 am
Posts: 1185
Location: Zurich, Switzerland
I didn't use this strategy before, but as far as I understood the documentation and the samples, the subclass mapping is not specified as its own mapping and another id mapping makes no sense, since the class already has an inherited id. Try the following:

Code:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                  assembly="Convergence.Libraries.Core"
                  namespace="Convergence.Libraries.Core.Entities">

  <class name="Player" table="Player" lazy="false">
    <id name="ID" column="ID" type="Int64">
      <generator class="assigned"/>
    </id>

    <property  name="Password" type="String" length="50" column="Password" not-null="true" />

    <joined-subclass name="Character" table="Character">
      <key column="ID"/>

      <property name="Name" type="String" length="50" column="Name"/>
      <property name="Health" type="Int32" column="Health"/>

    </joined-subclass>

  </class>
</hibernate-mapping>

_________________
--Wolfgang


Top
 Profile  
 
 Post subject:
PostPosted: Fri May 16, 2008 9:01 am 
Newbie

Joined: Thu May 15, 2008 10:51 pm
Posts: 8
Well trying your xml i now get a weird error...

Could not find a getter for property 'Password' in class 'Convergence.Libraries.Core.Entities.Character'

Why is it looking for a getter on the character class rather then the Player class where it is defined..

Also if i didn't remove the character xml from being an embedded resource then i would still get the dupe/key error. So my guess is that its nothing to do with the IDs but it trying to make another "Character" class and insert it into a dictionary of some sort (presume a cache of the proxy or reflected schema?)


This is what i'm trying to accomplish...

Code:
public interface IEntity
{
    long ID{get;set;}
}

public class Entity1 : IEntity
{
    public long ID {get;set;}
    public string Name {get;set;}
}

public class Entity2 : IEntity
{
    public long ID {get;set;}
    public string SomeOtherName{get;set;}
}

Table - Entities
bigint - ID - identity - not null

Table - Entity1
bigint - ID - foreign-key (Entities.ID) - not null
string - Name - not null

Table - Entity2
bigint - ID - foreign-key (Entities.ID) - not null
string - SomeOtherName - not null


As you can see that the entity interface has a identity id, but the inherited class 1 and 2 have a foreign-key to that identity column... It only makes sense to describe IEntity in xml, then describe Entity1 and 2 in their own xml file, if not you going to have to change Entity files (1,2) every time the schema changes on IEntity.



heres the xml i used for the new error
Code:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                  assembly="Convergence.Libraries.Core"
                  namespace="Convergence.Libraries.Core.Entities">
  <class name="Player" table="Player" lazy="false">
    <id name="ID" column="ID" type="Int64">
      <generator class="assigned"/>
    </id>

    <property  name="Password" type="String" length="50" column="Password" not-null="true" />

    <joined-subclass name="Character" table="Character">
      <key column="ID"/>

      <property name="Name" type="String" length="50" column="Name"/>
      <property name="Health" type="Int32" column="Health"/>

    </joined-subclass>

  </class>
</hibernate-mapping>


Top
 Profile  
 
 Post subject:
PostPosted: Fri May 16, 2008 9:21 am 
Expert
Expert

Joined: Thu Dec 14, 2006 5:57 am
Posts: 1185
Location: Zurich, Switzerland
Quote:
Also if i didn't remove the character xml from being an embedded resource then i would still get the dupe/key error. So my guess is that its nothing to do with the IDs but it trying to make another "Character" class and insert it into a dictionary of some sort (presume a cache of the proxy or reflected schema


Yes, you have to remove the Character.hbm.xml, because you already defined that class in the other mapping file.

Quote:
As you can see that the entity interface has a identity id, but the inherited class 1 and 2 have a foreign-key to that identity column... It only makes sense to describe IEntity in xml, then describe Entity1 and 2 in their own xml file, if not you going to have to change Entity files (1,2) every time the schema changes on IEntity.


If your interface only consists of the Id, then I would use a table-per-subclass strategy instead of the joined-subclass strategy. Besides that, you can define the <joined-subclass> in a separate hbm.xml file.

Quote:
Could not find a getter for property 'Password' in class 'Convergence.Libraries.Core.Entities.Character'


Do you still get this exception after removing the Character class mapping ?

_________________
--Wolfgang


Top
 Profile  
 
 Post subject:
PostPosted: Fri May 16, 2008 10:09 am 
Newbie

Joined: Thu May 15, 2008 10:51 pm
Posts: 8
Yes, that error is coming without the character xml file.


I guess i'm going to have to go back and look at some more tutorials...

I'm just trying to accomplish the following...


IEntity.hbm.xml
Code:
<xml>
  <identity ID>
</xml>


Entity1.hbm.xml
Code:
<xml>
  <foreign-key Entity_ID=IEntity.ID/>
  <name/>
  <subclass IEntity/>
</xml>


Entity2.hbm.xml
Code:
<xml>
  <foreign-key Entity_ID=IEntity.ID/>
  <SomeOtherName/>
  <subclass IEntity/>
</xml>


Is this possible in the first place? I don't want to have to redefine IEntity in each child entity file, it should be able to pull the information from the IEntity.hbm.xml file. In the end IEntity is going to be rather huge so it would make it a nightmare to managed it any other way.


Top
 Profile  
 
 Post subject:
PostPosted: Fri May 16, 2008 10:13 am 
Expert
Expert

Joined: Thu Dec 14, 2006 5:57 am
Posts: 1185
Location: Zurich, Switzerland
Yes, you can:

IEntity.hbm.xml
Code:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                  assembly="Convergence.Libraries.Core"
                  namespace="Convergence.Libraries.Core.Entities">
  <class name="Player" table="Player" lazy="false">
    <id name="ID" column="ID" type="Int64">
      <generator class="assigned"/>
    </id>
    <property  name="Password" type="String" length="50" column="Password" not-null="true" />
</hibernate-mapping>


Entity1.hbm.xml
Code:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                  assembly="Convergence.Libraries.Core"
                  namespace="Convergence.Libraries.Core.Entities">
    <joined-subclass name="Character" table="Character">
      <key column="ID"/>

      <property name="Name" type="String" length="50" column="Name"/>
      <property name="Health" type="Int32" column="Health"/>
    </joined-subclass>
  </class>
</hibernate-mapping>


For the exception, post your current mapping file(s).

_________________
--Wolfgang


Top
 Profile  
 
 Post subject:
PostPosted: Fri May 16, 2008 10:18 am 
Newbie

Joined: Thu May 15, 2008 10:51 pm
Posts: 8
I did.. its what you originally suggested and i reposted it in my 2nd post.

As for your reply... what about Entity2 and am i seeing that correctly that there is missing opening and closing xml tags?


Code:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                  assembly="Convergence.Libraries.Core"
                  namespace="Convergence.Libraries.Core.Entities">
  <class name="Player" table="Player" lazy="false">
    <id name="ID" column="ID" type="Int64">
      <generator class="assigned"/>
    </id>

    <property  name="Password" type="String" length="50" column="Password" not-null="true" />

    <joined-subclass name="Character" table="Character">
      <key column="ID"/>

      <property name="Name" type="String" length="50" column="Name"/>
      <property name="Health" type="Int32" column="Health"/>

    </joined-subclass>

  </class>
</hibernate-mapping>


This is causing the getter exception, its looking for the Password getting on the character class rather then the Player class


Last edited by xposure on Fri May 16, 2008 10:22 am, edited 2 times in total.

Top
 Profile  
 
 Post subject:
PostPosted: Fri May 16, 2008 10:20 am 
Newbie

Joined: Thu May 15, 2008 10:51 pm
Posts: 8
EDIT: Slow connection


Top
 Profile  
 
 Post subject:
PostPosted: Fri May 16, 2008 10:25 am 
Expert
Expert

Joined: Thu Dec 14, 2006 5:57 am
Posts: 1185
Location: Zurich, Switzerland
Quote:
As for your reply... what about Entity2 and am i seeing that correctly that there is missing opening and closing xml tags?


Sorry, copy&paste. </class> belongs to IEntity.

Entity2 can be defined the same way as Entity1. You just have <joined-sublass>...</joined-subclass> instead of <class>...</class> in your mapping file.

Can you post the code for Player and Character ? Just the fields and properties ?

_________________
--Wolfgang


Top
 Profile  
 
 Post subject:
PostPosted: Fri May 16, 2008 10:31 am 
Newbie

Joined: Thu May 15, 2008 10:51 pm
Posts: 8
Code:
    public class Character
    {
        public virtual long ID { get; private set; }
        public virtual string Name { get; private set; }
        public virtual string Health { get; private set; }
    }


    public class Player : Character
    {
        public virtual string Password { get; set; }
    }



Player xml
Code:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                  assembly="Convergence.Libraries.Core"
                  namespace="Convergence.Libraries.Core.Entities">
<class name="Player" table="Player" lazy="false">
    <id name="ID" column="ID" type="Int64">
      <generator class="assigned"/>
    </id>

    <property  name="Password" type="String" length="50" column="Password" not-null="true" />

    <joined-subclass name="Character" table="Character">
      <key column="ID"/>

      <property name="Name" type="String" length="50" column="Name"/>
      <property name="Health" type="Int32" column="Health"/>

    </joined-subclass>

  </class>
</hibernate-mapping>


Top
 Profile  
 
 Post subject:
PostPosted: Fri May 16, 2008 10:47 am 
Newbie

Joined: Thu May 15, 2008 10:51 pm
Posts: 8
EDIT:


Last edited by xposure on Fri May 16, 2008 10:53 am, edited 2 times in total.

Top
 Profile  
 
 Post subject:
PostPosted: Fri May 16, 2008 10:47 am 
Expert
Expert

Joined: Thu Dec 14, 2006 5:57 am
Posts: 1185
Location: Zurich, Switzerland
Character is mapped as a subclass of Player in opposite to your class hierarchy !

_________________
--Wolfgang


Top
 Profile  
 
 Post subject:
PostPosted: Fri May 16, 2008 11:00 am 
Newbie

Joined: Thu May 15, 2008 10:51 pm
Posts: 8
You are absolutely right. I was thinking of it completely backwards for whatever reason lol... Thank you for all your help.

i swapped the xml files around to use the correct <joined-subclass/> elements and i'm on track now. Everything is tested and loading fine.

Thanks again for all your help.

I'm not sure if its documented, but i didn't see creating a seperate file with <joined-subclass> as the start tag anywhere. Just a thought for the docs.


Top
 Profile  
 
 Post subject:
PostPosted: Fri May 16, 2008 11:43 am 
Expert
Expert

Joined: Thu Dec 14, 2006 5:57 am
Posts: 1185
Location: Zurich, Switzerland
In the source distribution you can find schema definitions for hibernate. If you copy them to C:\Program Files\Microsoft Visual Studio 8\Xml\Schemas (or wherever your VS is installed), you have IntelliSense support in the xml editor. It's not like documentation, but you can easily check what is allowed.

_________________
--Wolfgang


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