Usando Dapper.Net ORM, ¿cómo transfiero la salida del procedimiento almacenado a un tipo concreto?

c#-4.0 dapper metadata sql-server-2008-r2 stored-procedures

Pregunta

Usando Entity Framework puedo crear clases concretas desde la mayoría de los sprocs en la base de datos de un proyecto en el que estoy trabajando. Sin embargo, algunos de los sprocs usan SQL dinámico y, como tal, no se devuelven metadatos para el sproc.

Entonces, para ese sproc, creé manualmente una clase concreta y ahora quiero asignar la salida sproc a esta clase y devolver una lista de este tipo.

Usando el siguiente método, puedo obtener una colección de objetos:

                var results = connection.Query<object>("get_buddies", 
                    new {   RecsPerPage = 100,
                            RecCount = 0,
                            PageNumber = 0,
                            OrderBy = "LastestLogin",
                            ProfileID = profileID,
                            ASC = 1}, 
                        commandType: CommandType.StoredProcedure);

Mi clase concreta contiene

[DataContractAttribute(IsReference=true)]
[Serializable()]
public partial class LoggedInMember : ComplexObject
{

   /// <summary>
    /// No Metadata Documentation available.
    /// </summary>
    [EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
    [DataMemberAttribute()]
    public global::System.Int16 RowID
    {
        get
        {
            return _RowID;
        }
        set
        {
            OnRowIDChanging(value);
            ReportPropertyChanging("RowID");
            _RowID = StructuralObject.SetValidValue(value);
            ReportPropertyChanged("RowID");
            OnRowIDChanged();
        }
    }
    private global::System.Int16 _RowID;
    partial void OnRowIDChanging(global::System.Int16 value);
    partial void OnRowIDChanged();

    [EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
    [DataMemberAttribute()]
    public global::System.String NickName
    {
        get
        {
            return _NickName;
        }
        set
        {
            OnNickNameChanging(value);
            ReportPropertyChanging("NickName");
            _NickName = StructuralObject.SetValidValue(value, false);
            ReportPropertyChanged("NickName");
            OnNickNameChanged();
        }
    }
    private global::System.String _NickName;
    partial void OnNickNameChanging(global::System.String value);
    partial void OnNickNameChanged();
    .
    .
    .

Sin tener que repetir los resultados y agregar los parámetros de salida al objeto LoggedInMember, ¿cómo puedo asignarlos sobre la marcha para que pueda devolver una lista de ellos a través de un servicio WCF?

Si pruebo var results = connection.Query<LoggedInMember>("sq_mobile_get_buddies_v35", ... Recibo el siguiente error:

System.Data.DataException: Error al analizar la columna 0 (RowID = 1 - Int64) ---> System.InvalidCastException: El molde especificado no es válido. en Deserialize ...

Respuesta aceptada

La solución a esto fue crear un objeto complejo derivado del sproc con EF:

    public ProfileDetailsByID_Result GetAllProfileDetailsByID(int profileID)
    {
        using (IDbConnection connection = OpenConnection("PrimaryDBConnectionString"))
        {
            try
            {
                var profile = connection.Query<ProfileDetailsByID_Result>("sproc_profile_get_by_id",
                    new { profileid = profileID },
                    commandType: CommandType.StoredProcedure).FirstOrDefault();

                return profile;
            }
            catch (Exception ex)
            {
                ErrorLogging.Instance.Fatal(ex);        // use singleton for logging
                return null;
            }
        }
    }

En este caso, ProfileDetailsByID_Result es el objeto que creé manualmente utilizando Entity Framework mediante el proceso de creación de Tipo complejo (haga clic con el botón derecho en el diagrama modelo, seleccione Agregar / Tipo complejo ... o use el árbol Tipos complejos en el RHS).

UNA PALABRA DE PRECAUCIÓN

Debido a que las propiedades de este objeto se derivan del sproc, EF no tiene manera de saber si una propiedad es nulable. Para todos los tipos de propiedad que aceptan valores NULL, debe configurarlos manualmente seleccionando la propiedad y estableciendo su propiedad Nullable en true .


Respuesta popular

Supongo que su columna SQL es un bigint (es decir, Int64 aka long ) pero su tipo .Net tiene una propiedad Int16.

Puede jugar con la conversión e ignorar el procedimiento almacenado haciendo algo como:

var results = connection.Query<LoggedInMember>("select cast(9 as smallint) [RowID] ...");

Donde solo está seleccionando las propiedades y los tipos que desea devolver a su objeto. ( smallint es el equivalente SQL de Int16 )



Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow