首页 文章

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

提问于
浏览
11

更新 - 在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 回答

  • 5

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

    <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>()
    
  • 13

    问题解决了,虽然很明显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; }
        }
    }
    

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

    另请注意,为保存存储过程结果而创建的域类需要一个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>
    

相关问题