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

限于喜欢 提交于 2019-12-03 11:10:20

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>()
gb2d

Problem solved, although it seems apparent that NHibernate doesn’t want you using stored procedures. I am posting this to help others with the same issue, as this information was not easy to come by!

Initial blog that helped with this was here, though this example mapped the result back to a standard object - table mapping (which may be what you want). I wanted to map the result back to a custom object that did not have a table representation in the database:

http://forums.asp.net/t/1407518.aspx/1

So, I created a domain class to hold the stored procedure result.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MyProj.DataEntityTracker.Domain.Entities
{
    public class DemoCustomSprocObj
    {
        public virtual Guid Guid { get; set; }
        public virtual int ID { get; set; }
        public virtual string Name { get; set; }
    }
}

This class does not have to have a corresponding table in SQL server, although I found that a class definition does need to be created (with no table attribute) so as to avoid “NHibernate.MappingException: No persister for:” type errors.

Note also that the domain class that is created to hold the stored procedure result needs an ID field, and this must be returned from the database. In this case, I returned NEWID() from SQL Server and configured the mapping class to use the GUID generator for the ID field.

CREATE PROCEDURE usp_DemoCustomSproc
  @TrackedEntityID INT
AS
SET NOCOUNT ON
BEGIN
    SELECT NEWID() AS [Guid],
           ID ,
           Name 
    FROM TrackedEntityProperties AS tep
    WHERE TrackedEntityID = @TrackedEntityID
END

And the mapping class:

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

  <!-- This mapping does not use a table, rather it exists to
  allow the mapping of a stored procedure result back to a domain object. 
  Note the use of the GUID. An ID must be present and returned by the stored 
  procedure result, otherwise the object will not work with NHibernate.
  Note also the absence of a table in the class tag. No table exists in
  the database, but the mapping must exist to avoid "No persiter" errors.

  Arguments are passed with the :Arg syntax.

  It seems that NHibernate was not designed for use with stored procedures,
  though it may be useful to be able to use them in some situations. This
  is a means of doing so.

  -->

  <class name="DemoCustomSprocObj">
    <id name="Guid" type="guid" unsaved-value="00000000-0000-0000-0000-000000000000">
      <generator class="guid"></generator>
    </id>
    <property name="ID" />
    <property name="Name" />
  </class>

  <sql-query name="usp_DemoCustomSproc">
    <return alias="usp_DemoCustomSproc" class="DemoCustomSprocObj">

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

    </return>

    exec usp_DemoCustomSproc :TrackedEntityID

  </sql-query>

</hibernate-mapping>
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!