Appelez la procédure stockée depuis dapper qui accepte la liste des types de tables définis par l'utilisateur

c# dapper sql-server stored-procedures

Question

J'ai une procédure stockée InsertCars qui accepte la liste des types de tables définies par l'utilisateur 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

J'ai besoin d'appeler cette procédure stockée à partir de Dapper. Je l'ai googlé et trouvé des solutions.

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

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

Mais j'ai une erreur:

Procédure ou fonction InsertCars a trop d'arguments spécifiés

La procédure également stockée InsertCars renvoie le nombre de lignes insérées; J'ai besoin d'obtenir cette valeur.

Où est la racine du problème?

Mon problème est aussi que j'ai des voitures dans la liste générique List<Car> Cars et je veux passer cette liste pour stocker la procédure. Il existe une manière élégante comment le faire?

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

Merci pour l'aide

ÉDITÉ

J'ai trouvé des solutions

Dapper prend-il en charge les paramètres de la table SQL 2008?

ou

Dapper prend-il en charge les paramètres de la table SQL 2008 2?

Donc j'essaie de faire propre classe d'assistance stupide

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

Utilisation

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

Je reçois une exception

Lorsque vous utilisez les API multi-mapping, assurez-vous de définir le paramètre splitOn si vous avez des clés autres que Id.

Trace de la pile:

   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-ce qui ne va pas?

FIXÉ:

Appelez con.Execute place con.Query

Réponse acceptée

Mon problème est aussi que j'ai des voitures dans la liste générique des voitures et je veux passer cette liste pour stocker la procédure. Il existe une manière élégante comment le faire?

Vous devez convertir votre liste de véhicules génériques en fichier à enregistrer , puis la transmettre à la procédure stockée. Un point à noter est que l'ordre de vos champs doit être identique à celui défini dans le type de tableau défini par l'utilisateur dans la base de données. Sinon, les données ne seront pas enregistrées correctement. Et il doit également avoir le même nombre de colonnes .

J'utilise cette méthode pour convertir List en DataTable. Vous pouvez l'appeler comme 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;
    }

Réponse populaire

Je sais que c'est un peu vieux, mais je pensais que je posterais ça quand même, car j'ai cherché à rendre cela un peu plus facile. J'espère que je l'ai fait avec un package NuGet que je crée qui permettra un code comme:

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

Package NuGet: https://www.nuget.org/packages/Dapper.ParameterExtensions/0.2.0 Encore à ses débuts, il ne fonctionnera peut-être pas avec tout!

S'il vous plaît lire le fichier README et n'hésitez pas à contribuer sur GitHub: https://github.com/RasicN/Dapper-Parameters




Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi