Llamar al procedimiento almacenado de dapper, que acepta la lista del tipo de tabla definido por el usuario

c# dapper sql-server stored-procedures

Pregunta

Tengo un procedimiento almacenado InsertCars que acepta la lista del tipo de tabla definida por el usuario CarType .

CREATE TYPE dbo.CarType
AS TABLE
(
    CARID int null,
    CARNAME varchar(800) not null,
);

CREATE PROCEDURE dbo.InsertCars
    @Cars AS CarType READONLY
AS
-- RETURN COUNT OF INSERTED ROWS
END

Necesito llamar a este procedimiento almacenado de Dapper. Busqué en Google y encontré algunas soluciones.

 var param = new DynamicParameters(new{CARID= 66, CARNAME= "Volvo"});

 var result = con.Query("InsertCars", param, commandType: CommandType.StoredProcedure);

Pero me sale un error:

Procedimiento o función InsertCars tiene demasiados argumentos especificados

También procedimiento almacenado InsertCars devuelve el recuento de filas insertadas; Necesito obtener este valor.

¿Dónde está la raíz del problema?

Mi problema también es que tengo autos en la lista genérica List<Car> Cars y deseo pasar esta lista al procedimiento de almacenamiento. ¿Existe una manera elegante de cómo hacerlo?

public class Car
{
    public CarId { get; set; }
    public CarName { get; set; }
}

Gracias por ayudar

EDITADO

Encontré soluciones

¿Admite Dapper los parámetros con valores de tabla de SQL 2008?

o

¿Admite Dapper los Parámetros de valor de tabla de SQL 2008 2?

Así que intento hacer mi propia clase de ayuda estúpida

class CarDynamicParam : Dapper.SqlMapper.IDynamicParameters
{
    private Car car;

    public CarDynamicParam(Car car)
    {
        this.car = car;
    }

    public void AddParameters(IDbCommand command, SqlMapper.Identity identity)
    {
        var sqlCommand = (SqlCommand)command;

        sqlCommand.CommandType = CommandType.StoredProcedure;

        var carList = new List<Microsoft.SqlServer.Server.SqlDataRecord>();

        Microsoft.SqlServer.Server.SqlMetaData[] tvpDefinition =
                                                                {

                                                                    new Microsoft.SqlServer.Server.SqlMetaData("CARID", SqlDbType.Int),
                                                                    new Microsoft.SqlServer.Server.SqlMetaData("CARNAME", SqlDbType.NVarChar, 100),
                                                                };

        var rec = new Microsoft.SqlServer.Server.SqlDataRecord(tvpDefinition);
        rec.SetInt32(0, car.CarId);
        rec.SetString(1, car.CarName);

        carList.Add(rec);

        var p = sqlCommand.Parameters.Add("Cars", SqlDbType.Structured);
        p.Direction = ParameterDirection.Input;
        p.TypeName = "CarType";
        p.Value = carList;
    }
}

Utilizar

var result = con.Query("InsertCars", new CarDynamicParam(car), commandType: CommandType.StoredProcedure);

Me sale una excepción

Al usar las API de mapeo múltiple, asegúrese de configurar el parametro splitOn si tiene claves que no sean Id.

StackTrace:

   at Dapper.SqlMapper.GetDynamicDeserializer(IDataRecord reader, Int32 startBound, Int32 length, Boolean returnNullIfFirstMissing) in c:\Dev\Dapper\Dapper\SqlMapper.cs:line 1308
   at Dapper.SqlMapper.GetDeserializer(Type type, IDataReader reader, Int32 startBound, Int32 length, Boolean returnNullIfFirstMissing) in c:\Dev\Dapper\Dapper\SqlMapper.cs:line 1141
   at Dapper.SqlMapper.<QueryInternal>d__d`1.MoveNext() in c:\Dev\Dapper\Dapper\SqlMapper.cs:line 819
   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
   at Dapper.SqlMapper.Query[T](IDbConnection cnn, String sql, Object param, IDbTransaction transaction, Boolean buffered, Nullable`1 commandTimeout, Nullable`1 commandType) in c:\Dev\Dapper\Dapper\SqlMapper.cs:line 770
   at Dapper.SqlMapper.Query(IDbConnection cnn, String sql, Object param, IDbTransaction transaction, Boolean buffered, Nullable`1 commandTimeout, Nullable`1 commandType) in c:\Dev\Dapper\Dapper\SqlMapper.cs:line 715

¿Qué está mal?

FIJO:

Llamar a con.Execute en con.Query lugar con.Query

Respuesta aceptada

Mi problema también es que tengo autos en la lista genérica List Cars y quiero pasar esta lista al procedimiento de la tienda. ¿Existe una manera elegante de cómo hacerlo?

Necesita convertir su lista genérica de automóvil a una tabla de datos y luego pasarla a procedimiento almacenado . Un punto a tener en cuenta es que el orden de sus campos debe ser el mismo que el definido en el tipo de tabla definida por el usuario en la base de datos. De lo contrario, los datos no se guardarán correctamente. Y debe tener el mismo número de columnas también.

Yo uso este método para convertir List a DataTable. Puedes llamarlo como yourList.ToDataTable ()

public static DataTable ToDataTable<T>(this List<T> iList)
    {
        DataTable dataTable = new DataTable();
        PropertyDescriptorCollection propertyDescriptorCollection =
            TypeDescriptor.GetProperties(typeof(T));
        for (int i = 0; i < propertyDescriptorCollection.Count; i++)
        {
            PropertyDescriptor propertyDescriptor = propertyDescriptorCollection[i];
            Type type = propertyDescriptor.PropertyType;

            if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
                type = Nullable.GetUnderlyingType(type);


            dataTable.Columns.Add(propertyDescriptor.Name, type);
        }
        object[] values = new object[propertyDescriptorCollection.Count];
        foreach (T iListItem in iList)
        {
            for (int i = 0; i < values.Length; i++)
            {
                values[i] = propertyDescriptorCollection[i].GetValue(iListItem);
            }
            dataTable.Rows.Add(values);
        }
        return dataTable;
    }

Respuesta popular

Sé que esto es un poco viejo, pero pensé que publicaría sobre esto de todos modos ya que lo busqué para hacer esto un poco más fácil. Espero haberlo hecho con un paquete NuGet que creo que permitirá código como:

public class CarType
{
  public int CARID { get; set; }
  public string CARNAME{ get; set; }
}

var cars = new List<CarType>{new CarType { CARID = 1, CARNAME = "Volvo"}};

var parameters = new DynamicParameters();
parameters.AddTable("@Cars", "CarType", cars)

 var result = con.Query("InsertCars", parameters, commandType: CommandType.StoredProcedure);

Paquete NuGet: https://www.nuget.org/packages/Dapper.ParameterExtensions/0.2.0 ¡ Todavía está en sus primeras etapas, por lo que puede no funcionar con todo!

Lea el archivo README y no dude en contribuir en GitHub: https://github.com/RasicN/Dapper-Parameters



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