NHibernate - 如何映射到没有表的类(用于自定义sql查询)

时间:2011-05-04 13:03:21

标签: .net nhibernate fluent-nhibernate

  

更新 - 编辑配置以提高可读性   在SO

您好,

我一直在学习NHibernate一两天,但却陷入了困境。

我需要能够执行自定义存储过程并使用NHibernate将它们映射回域类。

我有这个工作用于自定义查询映射回映射到数据库表的对象的场景,如许多nhibernate示例所示(参见下面的第一部分)。

但是,在下面第二部分的配置中,查询仅从目标表中提取2列。出于这个原因,我创建了一个自定义对象,以便NHibernate可以将返回值映射到。自定义对象属性与自定义过程的返回列具有相同的名称。

当我运行测试时,我得到一个例外:

  

NHibernate.MappingException:没有   坚持:   Proj.DataEntityTracker.Domain.Entities.CustomObject

所以我认为sql-query部分下的映射不足以让NHibernate将返回值映射到对象属性。

所以我的问题是 - 如何设置数据库中没有等效表的映射,以便我可以将存储过程的结果映射到该对象?


<?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>

2 个答案:

答案 0 :(得分:13)

您正在寻找的是预测。首先,您需要修改您的查询

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

    exec usp_SomeCustomSproc :TrackedEntityID

  </sql-query>

然后在您调用它的代码中指定结果转换器。 AliasToBeanTransformer将获取列别名并将它们映射到对象上的属性。

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

答案 1 :(得分:5)

问题解决了,虽然很明显NHibernate不希望你使用存储过程。我发布这个是为了帮助其他人解决同样的问题,因为这些信息并不容易找到!

有关此问题的初始博客就在这里,尽管此示例将结果映射回标准对象 - 表映射(可能是您想要的)。我想将结果映射回一个在数据库中没有表格表示的自定义对象:

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

因此,我创建了一个域类来保存存储过程结果。

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; }
    }
}

这个类不必在SQL服务器中有相应的表,虽然我发现需要创建一个类定义(没有表属性),以避免“NHibernate.MappingException:No persister for:”type错误。

另请注意,为保存存储过程结果而创建的域类需要一个ID字段,并且必须从数据库返回。在这种情况下,我从SQL Server返回NEWID()并配置映射类以使用GUID生成器作为ID字段。

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

和映射类:

<?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>