views:

196

answers:

1

Consider these two classes mapped to the same table. One is readonly via mutable="false".

<class name="Funder" table="funder">
    <id name="id">
      <generator class="identity" />
    </id>
    <property name="funder_name" />
    <property name="contact_name" />
    <property name="addr_line_1" />
    <property name="addr_line_2" />
    <property name="addr_line_3" />
    <property name="city" />
    <many-to-one name="state" column="state_id" foreign-key="FK_funder_state_id" fetch="join" />
    <property name="zip_code" length="10" />
    <property name="phone_number" length="30" />

    <property name="create_dt" update="false" not-null="true" />
    <many-to-one name="create_by" column="create_by" not-null="true" update="false" foreign-key="FK_funder_create_by" fetch="join" />
    <property name="last_update_dt" insert="false" />
    <many-to-one name="last_update_by" insert="false" foreign-key="FK_funder_last_update_by" fetch="join" />

  </class>

  <class name="FunderSimple" table="funder" schema-action="none" mutable="false">
    <id name="id">
      <generator class="identity" />
    </id>
    <property name="funder_name" />
    <property name="contact_name" />
    <property name="phone_number" />
  </class>

If I move the FunderSimple mapping before the Funder mapping my schema does not generate correctly. If I leave it as is above, it works.

Is this by design? It seems as though the schema-action="none" sticks to the table_name and later mappings to the same table will not generate the schema.

I'm doing it like this because I have another class named Contract which has a foreign key to the funder table. However, I don't need all the funder columns when referencing from the contract object.

<many-to-one name="funder_simple" column="funder_id"  foreign-key="FK_contract_funder_id" fetch="join" />

Funder does not inherit from FunderSimple.

Should I be using a different technique to fetch only a subset of columns from a foreign key table? Is many-to-one the only way to setup a foreign key?

using version 2.1.0.4000

+1  A: 

For such situations, I use projections instead. I've never mapped two types to the same table (unless for inheritance reasons).

So, what I do in such a situation is:

create the FunderSimple class, and import it so that it is known by NHibernate:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
    <import class="MyNamespace.FunderSimple" />
</hibernate-mapping>

Once you've done this, you can create a query on your 'Funder' type, with the ICriteria API, but, you could specify that you would like NHibernate to return instances of FunderSimple. By doing so, NHibernate is smart enough to generate a simplified SQL query, that only retrieves the columns that are necessary to populate instances of the FunderSimple class.

This is done like this:

ICriteria crit = session.CreateCriteria (typeof(Funder));
// add some expressions ...
crit.Add ( ... );

// Now, set the projection, and specify that FunderSimple should be returned
crit.SetProjection (Projections.ProjectionList()
                         .Add (Projections.Property ("Id"), "Id")
                         .Add (Projections.Property ("funder_name"), "funder_name")
                         .Add (Projections.Property ("phone_number"), "phone_number"));

crit.SetResultTransformer (Transformers.AliasToBean (typeof(FunderSimple)));

crit.List <FunderSimple>();
Frederik Gheysels
interesting...But, how does this work from the Contract mapping perspective. Would I change the many-to-one back to the heavy Funder object and somehow map it to only load a FunderSimple?
dotjoe
Contract should have a relationship to 'Funder', since 'Funder' is your entity.I see FunderSimple only as some kind of helper/container in order to display a list of 'Funders', where you do not have the need to have the full blown Funder entity.Why would you like to retrieve 'FunderSimple' instances when you retrieve a Contract instance ?
Frederik Gheysels
Pretty much so I do not have to join all of the Funder's unneeded foreign-key's such as the create_by and last_update_by keys to a Staff table...which in turn results in more joins for a couple keys in the Staff table. The FunderSimple fields are the only ones I need as far as the Contract is concerned. I doubt it would hurt performance to join all these unneeded tables every time I fetch a Contract. But, I was just hoping there was a way to get around that and query only what I need.
dotjoe
The way I'm doing it above works like I want, but I don't know if it is even supported, since it's so fragile with the mapping order.
dotjoe
It is indeed fragile, and I wouldn't use it ...Can't you just use lazy loading for those extra entities (Create_By, LastUpdate_by) ?(I also keep track of audit information, but I just keep track of the name of the user inside the table itself; I do not join to some kind of 'Staff' table).
Frederik Gheysels
I suppose I probably should use lazy loading. I'm obviously pretty new to hibernate. I think I need to look into this UnitOfWork concept a little more. This is for a desktop app so I think I just need to figure out how to keep the session open whilst populating my view. Good advice on the projections...I can definitely use that in other areas. thanks.
dotjoe
Ah, I've seen the light with lazy loading. Very cool. I'm using projections in cases where I need to bind to a datagrid.
dotjoe
That's exactly how I'm doing it as well. :)When I need to display a large amount of data (in an overview (like a grid)), I use projections.
Frederik Gheysels