NHibernate - Как сопоставить классу, который не имеет таблицы (для пользовательских запросов SQL) - PullRequest
11 голосов
/ 04 мая 2011

Обновление - отредактированный конфиг для удобства чтения в 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 ]

13 голосов
/ 04 мая 2011

То, что вы ищете, - это прогнозы.Прежде всего вам нужно изменить ваш запрос

  <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>()
5 голосов
/ 04 мая 2011

Проблема решена, хотя кажется очевидным, что 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 ошибки.

Обратите внимание также, что классу домена, который создается для хранения результата хранимой процедуры, необходимо поле идентификатора, и это должно быть возвращено из базы данных. В этом случае я возвратил NEWID () из SQL Server и настроил класс сопоставления для использования генератора GUID для поля идентификатора.

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>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...