.net – NHibernate – How to map to a class that has no table (for custom sql queries)

fluent-nhibernatenetnhibernate

Update – Edited config for readability
in SO

Hi,

I've been learning NHibernate for a day or two but getting stuck on one point.

I need to be able to execute custom stored procedures and use NHibernate to map them back to domain classes.

I have this working for the scenario where the custom query maps back to a object that maps to a database table, as shown by many a nhibernate example (See first section below).

However in the config for the second section below, the query pulls only 2 columns from the target table. For this reason, I have created a custom object so that NHibernate has something to map the return values to. The custom object properties have the same name as the return columns from the custom procedure.

When I run my tests I get an exception like:

NHibernate.MappingException: No
persister for:
Proj.DataEntityTracker.Domain.Entities.CustomObject

So I guess the mapping under sql-query section is not enough for NHibernate to map the return values to the object properties.

So my question is – how do I set up a mapping for which there is no equivalent table in the database such that I can map the results of a stored procedure to that object?


<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                   assembly="Proj.DataEntityTracker.Domain"
                   namespace="Proj.DataEntityTracker.Domain.Entities">

  <class name="TrackedEntityProperty" table="TrackedEntityProperties">
    <id name="ID" type="Int32" unsaved-value="0">
      <generator class="native"></generator>
    </id>
    <property name="TrackedEntityID" />
    <property name="Name" />
    <property name="CreatedDate" />
    <property name="ChangedDate" />
    <property name="DataType" />
    <property name="CurrentValue" />
    <property name="RequestPropertyValueQuestion" />
    <property name="NullResponseIsAcceptable" />
    <property name="Duplication" />
    <property name="Frequency" />
    <property name="IsActive" />
    <property name="IsDeleted" />
    <property name="LastUpdateTaskGenerated" />
    <property name="LastUpdateTaskCompleted" />
    <property name="LastUpdateTaskCancelled" />
  </class>

  <sql-query name="usp_GetTrackedEntityPropertiesDueForUpdate" >
    <return alias="usp_GetTrackedEntityPropertiesDueForUpdate" class="TrackedEntityProperty">

      <return-property name="ID" column="ID" />
      <return-property name="TrackedEntityID" column="TrackedEntityID" />
      <return-property name="Name" column="Name" />
      <return-property name="CreatedDate" column="CreatedDate" />
      <return-property name="ChangedDate" column="ChangedDate" />
      <return-property name="DataType" column="DataType" />
      <return-property name="CurrentValue" column="CurrentValue" />
      <return-property name="RequestPropertyValueQuestion" column="RequestPropertyValueQuestion" />
      <return-property name="NullResponseIsAcceptable" column="NullResponseIsAcceptable" />
      <return-property name="Duplication" column="Duplication" />
      <return-property name="Frequency" column="Frequency" />
      <return-property name="IsActive" column="IsActive" />
      <return-property name="IsDeleted" column="IsDeleted" />
      <return-property name="LastUpdateTaskGenerated" column="LastUpdateTaskGenerated" />
      <return-property name="LastUpdateTaskCompleted" column="LastUpdateTaskCompleted" />
      <return-property name="LastUpdateTaskCancelled" column="LastUpdateTaskCancelled" />

    </return>

    exec usp_GetTrackedEntityPropertiesDueForUpdate :TrackedEntityID

  </sql-query>

  <sql-query name="usp_SomeCustomSproc">
    <return alias="usp_SomeCustomSproc" class="CustomObject">

      <return-property name="ID" column="ID" />
      <return-property name="Name" column="Name" />

    </return>

    exec usp_SomeCustomSproc :TrackedEntityID

  </sql-query>

</hibernate-mapping>

Best Answer

What you're looking for are projections. First of all you need to modify your query

  <sql-query name="usp_SomeCustomSproc">
    <return-scalar column="Id" type="Int32"/>
    <return-scalar column="Name" type="String"/>

    exec usp_SomeCustomSproc :TrackedEntityID

  </sql-query>

Then in the code where you call it you specify a result transformer. The AliasToBeanTransformer will take column aliases and map them to properties on the object.

session.GetNamedQuery("usp_SomeCustomSproc")
       .SetInt32("TrackedEntityID", 15)
       .SetResultTransformer(Transformers.AliasToBean<CustomObject>())
       .List<CustomObject>()
Related Topic