ユーザ定義のテーブルタイプのリストを受け入れるdapperからストアドプロシージャを呼び出す

c# dapper sql-server stored-procedures

質問

私はユーザー定義のテーブル型CarTypeリストを受け入れるストアドプロシージャInsertCarsを持っています。

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

Dapperからこのストアドプロシージャを呼び出す必要があります。私はそれを見つけ、いくつかの解決策を見つけました。

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

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

しかし、私はエラーが発生します:

プロシージャまたは関数InsertCarsの引数が多すぎます

また、ストアドプロシージャInsertCarsは挿入された行の数を返します。私はこの価値を得る必要があります。

問題の根はどこですか?

私の問題は、私はジェネリックリストList<Car> Cars車を持っており、このリストをストア手順に渡したいと思っています。どのようにそれを行うエレガントな方法が存在する?

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

ご協力ありがとうございます

EDITED

私は解決策を見つけた

DapperはSQL 2008のテーブル値パラメータをサポートしていますか?

または

DapperはSQL 2008テーブル値付きパラメータ2をサポートしていますか?

だから自分の愚かなヘルパークラスを作ろうとする

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

つかいます

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

私は例外を得る

マルチマッピングAPIを使用する場合は、Id以外のキーがある場合は必ずsplitOnパラメータを設定してください。

スタックトレース:

   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

なにが問題ですか?

一定:

con.Executeではなくcon.Query

受け入れられた回答

私の問題は、私はジェネリックリストのリストカーに車を持っているので、このリストをストア手順に渡したいと思います。どのようにそれを行うエレガントな方法が存在する?

ジェネリックリストCarをデータテーブル変換し、それをstoredprocedureに渡す必要があります。注目すべき点は、フィールドの順序は、データベース内のユーザー定義の表タイプ定義されているものと同じでなければならないということです。そうしないと、データが正しく保存されません。また、列数も同じなければなりません

このメソッドを使用してListをDataTableに変換します。 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;
    }

人気のある回答

私はこれが少し古いことを知っていますが、私はこれを少しでも簡単にするために探して以来、私はこれにとにかく投稿すると考えました。私が作成したNuGetパッケージを使って、以下のようなコードが可能になることを願っています。

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

NuGetパッケージ: https : //www.nuget.org/packages/Dapper.ParameterExtensions/0.2.0 まだ早い段階で、すべてで動作しない可能性があります。

READMEを読んで、GitHubに寄稿してくださいhttps : //github.com/RasicN/Dapper-Parameters



ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ
ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ