Даппер, как передать объект со списком объектов в хранимую процедуру

У меня проблема с выполнением существующей хранимой процедуры с помощью Dapper. Хранимая процедура принимает некоторые параметры и список объектов определяемого пользователем типа. Я имитировал необходимые параметры в C#, но некоторые преобразования проходят некорректно, что вызывает исключение (перечисленное ниже), и я не могу понять, как его решить.

Хранимая процедура SQL Server:

ALTER PROCEDURE [dbo].[MySp]
    @Name VARCHAR(60),
    @Size BIGINT,
    @Photos MyPhoto READONLY
AS
BEGIN
    -- ... logic

где MyPhoto — определяемый пользователем тип таблицы с:

Name VARCHAR(25),
Model VARCHAR(25)

На стороне C# у меня есть:

public class MyClassForSP
{
    public string Name { get; set; }
    public Int64 Size { get; set; }
    public List<Photos> Photos { get; set; }
}

public class Photos
{
    public string Name { get; set }
    public string Model { get; set; }
}

Пока что для меня все выглядит логично... поэтому я попытался выполнить SQL-запрос:

public void ExecuteSp(MyClassForSP classForSp)
{
    using IDbConnection connection = new SqlConnection(_settings.ConnectionString);

    var result = await connection.QuerySingleAsync<MyResult>("dbo.MySp", classForSp, 
    commandType: CommandType.StoredProcedure);
}

В результате я получаю ошибку Dapper:

System.NotSupportedException: «Член типа MyNameSpace.Photos нельзя использовать в качестве значения параметра»

Это может помочь — Параметр с табличным значением Dapper. По сути, вы не можете передать перечисляемое напрямую и ожидать неявного перевода в свой TVP. Сначала вам нужно создать таблицу данных в правильном формате, а затем передать ее в качестве параметра, используя DataTable.AsTableValuedParameter()

GarethD 19.04.2024 17:17
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
1
266
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вам необходимо использовать табличный параметр, указав DataTable.

DataTable dt = new DataTable();
dt.Columns.Add("Name");
dt.Columns.Add("Model");

foreach (var photo in classForSp.Photos) 
{
    dt.Rows.Add(photo.Name, photo.Model);
}

using IDbConnection connection = new SqlConnection(_settings.ConnectionString);
var result = await connection.QuerySingleAsync<MyResult>("dbo.MySp", 
    new 
    { 
        Name = classForSp.Name, 
        Size = classForSp.Size, 
        Photos = dt.AsTableValuedParameter("MyPhoto") 
    }, 
    commandType: CommandType.StoredProcedure);

Если вы ищете общий способ преобразования списка в DataTable для параметра с табличным значением, вы можете реализовать метод расширения, как показано ниже:

public static class IListExtensions
{
    public static DataTable ToDataTable<T>(this IList<T> list)
    {
        PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(T));
        DataTable dataTable = new DataTable();

        foreach (PropertyDescriptor property in properties)
            dataTable.Columns.Add(property.Name, Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType);

        foreach (T item in list)
        {
            DataRow row = dataTable.NewRow();
            foreach (PropertyDescriptor property in properties)
                row[property.Name] = property.GetValue(item) ?? DBNull.Value;

            dataTable.Rows.Add(row);
        }

        return dataTable;
    }
}

Звонивший:

DataTable dt = classForSp.Photos.ToDataTable();

Это работает, но есть ли у нас более удобные способы преобразования класса данных в параметры без дополнительного ввода тех же имен параметров?

Jivopis 19.04.2024 20:14

Привет, насколько я понимаю, вы хотите преобразовать класс данных в DataTable общим способом? Если да, я добавляю свой ответ о написании метода расширения для преобразования в DataTable. Демо

Yong Shun 20.04.2024 02:28

Другие вопросы по теме