tags:

views:

113

answers:

2

I have a class structure like the following

class Container
{
    public virtual int Id { get; set; }
    public IList<Base> Bases { get; set; }
}

class Base
{
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
}

class EnemyBase : Base
{
    public virtual int EstimatedSize { get; set; }
}

class FriendlyBase : Base
{
    public virtual int ActualSize { get; set; }
}

Now when I ask the session for a particular Container it normally gives me the concrete EnemyBase and FriendlyBase objects in the Bases collection. I can then (if I so choose) cast them to their concrete types and do something specific with them.

However, sometime I get a proxy of the "Base" class which is not castable to the concrete types. The same method is used both times with the only exception being that in the case that I get proxies I have added some related entities to the session (think the friendly base having a collection of people or something like that).

Is there any way I can prevent it from doing the proxy creating and why would it choose to do this in some scenarios?

UPDATE

The mappings are generated with the automap feature of fluentnhibernate but look something like this when exported

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-access="property" auto-import="true" default-cascade="none" default-lazy="true">
  <class xmlns="urn:nhibernate-mapping-2.2" mutable="true" name="Base" table="`Base`">
    <id name="Id" type="System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="Id" />
      <generator class="MyIdGenerator" />
    </id>
    <property name="Name" type="String">
      <column name="Name" />
    </property>

    <joined-subclass name="EnemyBase">
      <key>
        <column name="Id" />
      </key>
      <property name="EstimatedSize" type="Int">
        <column name="EstimatedSize" />
      </property>

    </joined-subclass>
    <joined-subclass name="FriendlyBase">
      <key>
        <column name="Id" />
      </key>
      <property name="ActualSize" type="Int">
        <column name="ActualSize" />
      </property>

    </joined-subclass>
  </class>
</hibernate-mapping>

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-access="property" auto-import="true" default-cascade="none" default-lazy="true">
  <class xmlns="urn:nhibernate-mapping-2.2" mutable="true" name="Container" table="`Container`">
    <id name="Id" type="System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="Id" />
      <generator class="MyIdGenerator" />
    </id>
    <bag cascade="all-delete-orphan" inverse="true" lazy="false" name="Bases" mutable="true">
      <key>
        <column name="ContainerId" />
      </key>
      <one-to-many class="Base" />
    </bag>  
  </class>
</hibernate-mapping>

UPDATE

I've now told NH to never lazy load anything it automaps, not ideal if I need the feature in the future but it seems to be working for now.

A: 

Can you define the type as abstract? This will probably give you an error since nHibernate is trying anyway but it might point you towards a "why".

Spencer Ruport
I've marked it as abstract with exactly the same results.
Chris Meek
A: 

As I understand it, if you use myProxiedBase = Session.Load<Base>(myBase.Id) you will always get a proxy of a Base object. If you WANT an EnemyBase object you have to make another call to Session.Load<EnemyBase<(myProxiedBase.Id).

Check this section of Chapter 17 in the Docs:

It explains it a bit better than I can, and possible workarounds.

snicker
In this case I'm getting the Container object, not directly getting one of the "Base" classes. Normally the collection fills up fine with the concrete classes unless I've done something else in the session first. I'm just not sure what triggers it
Chris Meek
If you have other objects that have references to Base objects and you load them, it may create the proxies as Base objects and cache them in the session. I'm assuming you are lazy loading your entities?
snicker
In this case I've told it not to since the container always needs its children (I only use it on one page at the moment)
Chris Meek