Динамическое создание моделей DTO на основе данных, возвращаемых хранимой процедурой

У меня есть сценарий, в котором я передаю имя таблицы в качестве параметра хранимой процедуре SQL Server, и она возвращает данные из этой таблицы.

Структура данных, возвращаемая хранимой процедурой, зависит от параметра (имени таблицы), который я ей передаю.

В моей существующей реализации, где структура данных фиксирована, т. е. столбцы, возвращаемые хранимой процедурой, не изменяются, мы используем предопределенные DTO, которые выглядят следующим образом:

public IList<UserDetailsDTO> GetUserDetails(int userId)
{
    Dictionary<string, object> params = new Dictionary<string, object>();
    params.Add("@UserId",userId);

    return ExecuteProcedure<UserDetailsDTO>("spGetUserDetails", params);
}

Теперь, учитывая мое новое требование, согласно которому структура данных, возвращаемая хранимой процедурой, варьируется в зависимости от передаваемого ей параметра имени таблицы, я не уверен, как я могу сделать мои DTO динамическими.

Есть какие-нибудь отзывы или предложения по этому поводу?

«я передаю имя таблицы в качестве параметра хранимой процедуре SQL Server, и эта хранимая процедура возвращает данные из этой таблицы» такая настройка часто является признаком проблемы XY.

Thom A 05.08.2024 20:59

@GustavoOliveira В настоящее время приложение настроено с использованием ADO.NET.

Sayan 05.08.2024 21:02

Реляционные базы данных не предназначены/не предназначены для общего/DRY-кода. Они предназначены для конкретного статического кода.

Dale K 05.08.2024 21:43

Как ваше приложение будет использовать полученные значения? Если у вас есть разные места в коде, в которые передаются разные жестко запрограммированные параметры таблицы, и вы знаете, какой тип значения следует ожидать, вы можете использовать универсальный тип в своем вспомогательном методе. Если вызывающий код просто передает значения куда-то еще (например, для сериализации), вы можете просто использовать словарь.

StriplingWarrior 05.08.2024 21:46

@StriplingWarrior Имя таблицы будет передано из внешнего интерфейса на основе выбора раскрывающегося списка. Как только уровень доступа к данным вернет значения, эти значения будут возвращены на бизнес-уровень и с бизнес-уровня на контроллер API и метод действия контроллера API. вернет форму массива JSON, который будет использоваться в FE и отобразит набор результатов в сетке.

Sayan 05.08.2024 22:00

Зачем вам вообще нужны DTO? Похоже, вы просто хотите получить JSON прямо сейчас.

siggemannen 05.08.2024 23:16
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
7
55
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы делаете это точно так же, с фиксированным DTO для каждого вызова базы данных, даже если у вас есть одна хранимая процедура, которая возвращает разные наборы результатов (что является раздражающим и бесполезным шаблоном). например

public IList<UserDetailsDTO> GetUserDetails(int userId)
{
    Dictionary<string, object> params = new Dictionary<string, object>();
    params.Add("@Id",userId);
    params.Add("@EntityName","UserDetails");

    return ExecuteProcedure<UserDetailsDTO>("usp_GetWhatever", params);
}

«Это раздражающая и бесполезная закономерность» ✅

Dale K 05.08.2024 22:04

Нужно ли мне иметь несколько методов в DAL с фиксированным DTO для каждого параметра?

Sayan 05.08.2024 22:11

Вам следует. Но если вместо этого вы используете отражение, ваш компьютер не загорится. А если у вас нет типов DTO, вам придется сгенерировать JSON в коде. Опять же, то, что вы могли бы сделать, но я бы не стал.

David Browne - Microsoft 05.08.2024 22:12

Я читаю здесь между строк и предполагаю, что, возможно, схема базы данных на самом деле не связана с доменом приложения, и в этом случае было бы нецелесообразно менять код для добавления DTO каждый раз при изменении таблицы.

StriplingWarrior 05.08.2024 23:42
Ответ принят как подходящий

Я бы рекомендовал прочитать возвращенные строки в нечто вроде Dictionary<string, object>, как описано здесь.

List<Dictionary<string, object>> items = new List<Dictionary<string, object>>();
using (var reader = await command.ExecuteReaderAsync())
{
    if (reader.HasRows)
    {
        while (await reader.ReadAsync())
        {
            Dictionary<string, object> obj = new Dictionary<string, object>();

            for (int i = 0; i < reader.FieldCount; i++)
            {
                string columnName = reader.GetName(i);
                object columnValue = reader.GetValue(i);
                obj[columnName] = columnValue;
            }
            items.Add(obj);
        }
    }
}

Затем просто попросите вашу функцию вернуть этот список для сериализации.

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

Невозможно одновременно вызывать асинхронные методы в правильном порядке в C#
Ищете алгоритм или подход для сравнения значений двух строк (.NET)
Определить, удален ли управляемый объект
Blazor EditForm: кнопка отключения приводит к тому, что все нетронутые поля помечаются как недействительные
.NET 8: MemoryCache SlidingExpiration без доступа
Изменение цвета фона панели задач на прозрачный через Win32 API или реестр в Windows 11
Проблема развертывания Blazor WASM Core в Azure
Netwonsoft JsonConvert.Deserialization выдает исключение JsonSerializationException: «Ошибка преобразования значения «Имя моего пользовательского объекта» в тип «System.Type»
Как обеспечить автоматическое масштабирование для CollectionView в объекте Popup из CommunityToolkit.Maui после его заполнения с помощью события нажатия кнопки на платформе Windows?
«Попытка чтения или записи защищенной памяти. Часто это признак того, что другая память повреждена». В программе на C#