Сопоставление строго типизированных наборов данных в универсальном методе FillDataSet в C#?

Редактировать: Я использую SqlDataAdapters для заполнения наборов данных. Извините, я должен был быть более ясным.

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

public static DataSet FillDataSet(DataSet dataSet, string storedProcedureName, Dictionary<string, string> parameters);

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

  • Добавьте новый формальный элемент к моему методу FillDataSet (KeyValuePair<string, string>[] mappings), который предоставит информацию для сопоставлений таблиц.
  • Создайте DataSetMappingFactory, который будет принимать DataSet в качестве параметра, а затем добавить соответствующие сопоставления в зависимости от его типа. Если бы это был неизвестный тип, он бы не добавил никаких сопоставлений. Затем он вернет DataSet методу FillDataSet.

Есть ли у кого-нибудь из вас другие мысли о том, как я могу подойти к этой проблеме? Кроме того, хочет ли кто-нибудь взвесить подход, который был бы лучшим с точки зрения объектно-ориентированного проектирования?

Какой механизм вы используете для заполнения различных таблиц данных? Читатель данных? TableAdapters? Что-то другое?

Ryan Lundy 23.10.2008 21:57

Я использую SqlDataAdapters. Я обновил вопрос, чтобы прояснить это. :)

Ed Altorfer 23.10.2008 22:57
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать 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
2
3 346
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Первый вопрос, который я задам: действительно ли мне вообще нужно это делать? Типизированный конструктор DataSet уже предоставляет вам инструмент для определения сопоставления между хранимой процедурой и DataTable. Если вы тщательно разрабатываете свой DataSet, у вас уже есть метод Fill для каждого DataTable. Есть ли смысл изобретать это колесо?

Думаю, может. Это действительно здорово, что есть способ поддерживать это отображение, но все в этом отображении замораживается во время компиляции. Если вы хотите изменить сопоставление, вам необходимо перестроить сборку. Также типизированный дизайн DataSet не работает с хранимыми процедурами, которые возвращают несколько наборов результатов. Если вы хотите в общем сопоставить параметры и значения, вам нужно использовать отражение, чтобы получить списки аргументов из методов Fill. Может случиться так, что если вы посмотрите на эти факторы (и другие, о которых я не думаю), работа с существующим инструментом - не лучший вариант.

В этом случае мне кажется, что ваша цель - иметь возможность заполнить DataSet из ряда хранимых процедур кодом, который знает как можно меньше о деталях реализации. Так что это процесс, который будет управляться метаданными. Когда у вас есть процесс, управляемый метаданными, в конечном итоге для вас будет иметь наибольшее значение, насколько легко будет поддерживать метаданные, используемые процессом. Как только вы заставите код работать, вы, вероятно, не будете сильно его трогать. Но вы будете постоянно настраивать метаданные.

Если я посмотрю на проблему с этой точки зрения, первое, что я думаю сделать, - это разработать типизированный DataSet, содержащий метаданные. Это дает нам кучу вещей, которые в противном случае нам пришлось бы выяснить:

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

В этом DataSet у вас будет таблица DataSetType, привязанная к типу каждого типизированного DataSet, который вы собираетесь заполнять. У него будет дочерняя таблица StoredProcedures со строкой для каждого вызываемого SP. Это будет иметь две дочерние таблицы, Parameter и DataTableType. Будет одна строка DataTableType, упорядоченная по порядковому номеру, для каждого набора результатов, который должен вернуть SP. Таблица DataTableType будет иметь дочернюю таблицу ColumnMapping. Именно в этой таблице вы будете поддерживать сопоставления между столбцами в наборе результатов и столбцами в таблице, которую вы заполняете.

Убедитесь, что все ваши отношения DataRelations вложены, и что вы дали отношениям рациональные имена. (Мне нравится FK_childtablename_parenttablename.)

Как только у вас есть это, дизайн класса становится довольно простым. У класса есть ссылка на набор метаданных, DataSet, Connection и т. д., И он предоставляет метод с этой сигнатурой:

public void FillDataSet(DataSet targetDs, Dictionary<string, Dictionary<string, KeyValuePair<string, string>> parameterMap);

Вы начинаете с использования типа targetDs, чтобы найти строку DataSetType верхнего уровня. Затем все частные методы перебирают списки DataRows, возвращаемые DataTable.GetChildRows (). И вы добавляете одно или два события в конструкцию класса, чтобы во время выполнения операции он мог вызывать события, чтобы вызывающее приложение узнало, как оно продвигается.

Вероятно, первое, что я ожидал от рефакторинга этого дизайна, - это дать мне более точный контроль над процессом заполнения. Например, согласно проекту, на каждый типизированный DataSet существует только один набор SP. Что, если я хочу заполнить только часть DataSet? По задумке, я не могу. Но вы можете легко сделать первичный ключ таблицы DataSetType из двух частей, с частями, являющимися типом DataSet и некоторым строковым ключом (с таким именем, как SPSetName или OperationName), и добавить вторую часть ключа в список аргументов FillDataSet. .

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

Ed Altorfer 24.10.2008 00:46

Если вам нужно сохранить свои метаданные и / или вы хотите иметь возможность изменять их без перекомпоновки / повторного развертывания вашего программного обеспечения, накладные расходы внезапно выглядят довольно небольшими.

Robert Rossney 24.10.2008 23:02

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