Редактировать: Я использую SqlDataAdapters для заполнения наборов данных. Извините, я должен был быть более ясным.
Я работаю над проектом, в котором мне нужно заполнить ряд строго типизированных наборов данных информацией из хранимых процедур. Прямо сейчас у меня есть общий метод на уровне доступа к данным:
public static DataSet FillDataSet(DataSet dataSet, string storedProcedureName, Dictionary<string, string> parameters);
Проблема в том, что мне нужно установить сопоставления между наборами записей, возвращаемыми из хранимой процедуры, и таблицами в моих наборах данных. Я придумал для этого два варианта:
FillDataSet (KeyValuePair<string, string>[] mappings), который предоставит информацию для сопоставлений таблиц.DataSetMappingFactory, который будет принимать DataSet в качестве параметра, а затем добавить соответствующие сопоставления в зависимости от его типа. Если бы это был неизвестный тип, он бы не добавил никаких сопоставлений. Затем он вернет DataSet методу FillDataSet.Есть ли у кого-нибудь из вас другие мысли о том, как я могу подойти к этой проблеме? Кроме того, хочет ли кто-нибудь взвесить подход, который был бы лучшим с точки зрения объектно-ориентированного проектирования?
Я использую SqlDataAdapters. Я обновил вопрос, чтобы прояснить это. :)





Первый вопрос, который я задам: действительно ли мне вообще нужно это делать? Типизированный конструктор 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. .
Это очень интересный подход к решению моей проблемы. Я не уверен, буду ли я использовать его из-за накладных расходов, которые он добавит к моему проекту, но мне нравится, что информация будет определяться наборами данных.
Если вам нужно сохранить свои метаданные и / или вы хотите иметь возможность изменять их без перекомпоновки / повторного развертывания вашего программного обеспечения, накладные расходы внезапно выглядят довольно небольшими.
Какой механизм вы используете для заполнения различных таблиц данных? Читатель данных? TableAdapters? Что-то другое?