2011-05-04 9 views
11

Actualización - Editado config para facilitar la lectura en SONHibernate - ¿Cómo asignar a una clase que no tiene ninguna mesa (para consultas SQL personalizado)

Hola,

He estado aprendiendo NHibernate por un día o dos pero quedando atrapado en un punto.

Necesito ser capaz de ejecutar procedimientos almacenados personalizados y utilizar NHibernate para asignarlos de nuevo a clases de dominio.

Esto funciona para el escenario donde la consulta personalizada se correlaciona con un objeto que se asigna a una tabla de base de datos, como se muestra en muchos ejemplos de nhibernate (consulte la primera sección a continuación).

Sin embargo, en la configuración de la segunda sección a continuación, la consulta extrae solo 2 columnas de la tabla de destino. Por esta razón, he creado un objeto personalizado para que NHibernate tenga algo para mapear los valores de retorno. Las propiedades de objeto personalizado tienen el mismo nombre que las columnas de retorno del procedimiento personalizado.

Cuando ejecuto mis pruebas me sale una excepción como:

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

así que supongo que la la asignación en la sección sql-query no es suficiente para que NHibernate correlacione los valores devueltos con las propiedades del objeto.

Así que mi pregunta es: ¿cómo puedo configurar una asignación para la que no hay una tabla equivalente en la base de datos para poder asignar los resultados de un procedimiento almacenado a ese objeto?

 

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

Respuesta

13

Lo que estás buscando son proyecciones. En primer lugar, debe modificar su consulta

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

    exec usp_SomeCustomSproc :TrackedEntityID 

    </sql-query> 

Luego, en el código donde lo llame, especifique un transformador de resultados. AliasToBeanTransformer tomará alias de columna y los correlacionará con las propiedades del objeto.

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

Gracias, esto es realmente útil – gb2d

5

Problema resuelto, aunque parece evidente que NHibernate no quiere que use los procedimientos almacenados. Estoy publicando esto para ayudar a otros con el mismo problema, ¡ya que esta información no fue fácil de obtener!

El blog inicial que ayudó con esto estaba aquí, aunque este ejemplo asignó el resultado a un mapeo de tabla de objetos estándar (que puede ser lo que desee). Quería asignar el resultado a un objeto personalizado que no tienen una representación en tabla de la base de datos:

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

tanto, he creado una clase de dominio para mantener el resultado del procedimiento almacenado.

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

Esta clase no tiene que tener una tabla correspondiente en el servidor SQL, aunque me pareció que una definición de clase necesita ser creado (sin atributo de la tabla) a fin de evitar “NHibernate.MappingException: No persister para: "tipo errores".

Tenga en cuenta también que la clase de dominio que se crea para contener el resultado del procedimiento almacenado necesita un campo ID, y esto se debe devolver desde la base de datos. En este caso, devolví NEWID() desde SQL Server y configuré la clase de asignación para usar el generador GUID para el campo 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 

Y la clase de asignación:

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

Adición de la clase fijado mis problemas de consulta con nombre también. ¡Gracias! – Alex

Cuestiones relacionadas