사용자 정의 테이블 유형의 목록을 수용하는 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; }
}

도와 줘서 고마워

편집 됨

솔루션을 찾았습니다.

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 매개 변수를 설정해야합니다.

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

뭐가 잘못 되었 니?

결정된:

con.Execute 대신 con.Query 호출 con.Execute

수락 된 답변

내 문제는 또한 일반 목록 자동차에 자동차가 있고이 목록을 저장 프로 시저에 전달하고 싶습니다. 그것을하는 우아한 방법 존재 하는가?

일반 목록 Car를 datatable로 변환 한 다음 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
아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow