views:

168

answers:

0

Hi, I am getting the error below:

Object with id: 34dd93d3-374e-df11-9667-001aa03fa2c4 was not of the specified subclass: MyNamespace.ClassA (loading object was of wrong class [MyNamespace.ClassB1])

Call stack is:

at NHibernate.Loader.Loader.InstanceAlreadyLoaded(IDataReader rs, Int32 i, IEntityPersister persister, EntityKey key, Object obj, LockMode lockMode, ISessionImplementor session)
at NHibernate.Loader.Loader.GetRow(IDataReader rs, ILoadable[] persisters, EntityKey[] keys, Object optionalObject, EntityKey optionalObjectKey, LockMode[] lockModes, IList hydratedObjects, ISessionImplementor session)
at NHibernate.Loader.Loader.GetRowFromResultSet(IDataReader resultSet, ISessionImplementor session, QueryParameters queryParameters, LockMode[] lockModeArray, EntityKey optionalObjectKey, IList hydratedObjects, EntityKey[] keys, Boolean returnProxies)
at NHibernate.Loader.Loader.DoQuery(ISessionImplementor session, QueryParameters queryParameters, Boolean returnProxies)
at NHibernate.Loader.Loader.DoQueryAndInitializeNonLazyCollections(ISessionImplementor session, QueryParameters queryParameters, Boolean returnProxies)
...
at NHibernate.Linq.CriteriaResultReader1.<GetEnumerator>d__0.MoveNext()
at System.Collections.Generic.List
1..ctor(IEnumerable1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable
1 source)

I have renamed my classes and took out the irrelevant properties and such, to simplify, but the levels of inheritance are exactly like in my real scenario.

The classes:

public abstract class BaseClass : 
{
    public Guid ID { get; set; }
    ...

}
public abstract class ClassA : BaseClass
{
    public ClassB RelatedObject { get; set; }
}
public abstract class ClassB : BaseClass
{
    public ClassA RelatedObject { get; set; }
}
public abstract class ClassC : BaseClass
{
    ...
}

public class ClassA1 : ClassA
{
    ...
}
public class ClassA2 : ClassA
{
    ...
}

public class ClassB1 : ClassB
{
    ...
}
public class ClassB2 : ClassB
{
    ...
}

public class ClassC1 : ClassC
{
    ...
}
public class ClassC2 : ClassC
{
    ...
}

There is a table for the base class, and then individual tables for some of the concrete classes, not all of them. The corresponding column for the related object is in the main table.

BaseClassTable:
-------------------------------
| ID | Kind | RelatedObjectID |
-------------------------------

Individual tables:
---------------------------------
| ID | some specific properties |
---------------------------------

Mapping is:

<class name="MyNamespace.BaseClass, MyNamespace" table="BaseClassTable" discriminator-value="BC" abstract="true">
    <id name="ID" type="System.Guid" column="ID" unsaved-value="00000000-0000-0000-0000-000000000000">
      <generator class="guid" />
    </id>
    <discriminator column="Kind" type="System.String"/>
    ...
    <subclass name="MyNamespace.ClassA, MyNamespace" discriminator-value="A" abstract="true">
        <many-to-one name="RelatedObject" class="MyNamespace.ClassB, MyNamespace" column="RelatedObjectID"/>
    </subclass>
    <subclass name="MyNamespace.ClassB, MyNamespace" discriminator-value="B" abstract="true">
        <many-to-one name="RelatedObject" class="MyNamespace.ClassA, MyNamespace" column="RelatedObjectID"/>
    </subclass>
    <subclass name="MyNamespace.ClassC, MyNamespace" discriminator-value="C" abstract="true">
    ...
    </subclass>
  </class>
  <subclass name="MyNamespace.ClassA1, MyNamespace" extends="MyNamespace.ClassA, MyNamespace" discriminator-value="A1">
    <join table="ClassA1Table">
        <key column="ID"/>
        ...
    </join> 
    ...
  </subclass>
  <subclass name="MyNamespace.ClassA2, MyNamespace" extends="MyNamespace.ClassA, MyNamespace" discriminator-value="A2">
    ...
  </subclass>
  <subclass name="MyNamespace.ClassB1, MyNamespace" extends="MyNamespace.ClassB, MyNamespace" discriminator-value="B1">
    ...
  </subclass>
  <subclass name="MyNamespace.ClassB2, MyNamespace" extends="MyNamespace.ClassB, MyNamespace" discriminator-value="B2">
    ...
  </subclass>
  <subclass name="MyNamespace.ClassC1, MyNamespace" extends="MyNamespace.ClassC, MyNamespace" discriminator-value="C1">
    ...
      </subclass>
  <subclass name="MyNamespace.ClassC2, MyNamespace" extends="MyNamespace.ClassC, MyNamespace" discriminator-value="C2">
    ...
  </subclass>

Of course, in the DB I’m only going to have the A1, A2, B1, B2, C1 and C2 values for the discriminator.

Did anybody run into something like this before? Can a property be mapped as a base class and then have an instance of the concrete class loaded, for the same ID? Is there a better way to accomplish this? Thank you!

This is the call that throws the exception:

The error is thrown when trying to retrieve objects using the IQueryable from my data context:

List<MyNamespace.BaseClass> items = context.MyObjects.ToList();

And in my data context, the IQueryable property looks like this:

IQueryable<MyNamespace.BaseClass> IMyDataContext.MyObjects
{
   get
   {
      return this.Session.Linq<MyNamespace.BaseClass>();
   }
}