Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Замечание
Классы DataSet и связанные классы являются устаревшими технологиями .NET Framework с начала 2000-х годов, которые позволяют приложениям работать с данными в памяти, пока приложения отключены от базы данных. Технологии особенно полезны для приложений, которые позволяют пользователям изменять данные и сохранять изменения обратно в базу данных. Хотя наборы данных являются проверенными успешными технологиями, рекомендуемый подход для новых приложений .NET заключается в использовании Entity Framework Core. Entity Framework предоставляет более естественный способ работы с табличными данными в виде объектных моделей и имеет более простой интерфейс программирования.
Набор данных — это копия данных в памяти. При изменении этих данных рекомендуется сохранить эти изменения обратно в базу данных. Это можно сделать одним из трех способов:
Вызов одного из
Update
методов TableAdapterВызов одного из
DBDirect
методов TableAdapterВызов метода
UpdateAll
в TableAdapterManager, который Visual Studio создает для вас, когда в наборе данных имеются таблицы, связанные с другими таблицами.
При привязке таблиц наборов данных к элементам управления на странице Windows Form или XAML архитектура привязки данных выполняет всю работу.
Если вы знакомы с TableAdapters, вы можете перейти непосредственно к одному из следующих разделов:
Тема | Описание |
---|---|
Вставка новых записей в базу данных | Как выполнять обновления и вставки с помощью объектов TableAdapters или Command |
Обновление данных с помощью TableAdapter | Как выполнять обновления с помощью TableAdapters |
иерархическое обновление | Как выполнять обновления из набора данных с двумя или более связанными таблицами |
Обработка исключения параллелизма | Обработка исключений при попытке двух пользователей одновременно изменить одни и те же данные в базе данных |
Практическое руководство. Сохранение данных с помощью транзакции | Как сохранить данные в транзакции с помощью системы. Пространство имен транзакций и объект TransactionScope |
Сохранение данных в транзакции | Пошаговое руководство по созданию приложения Windows Forms для демонстрации сохранения данных в базе данных внутри транзакции |
Сохранение данных в базе данных (несколько таблиц) | Изменение записей и сохранение изменений в нескольких таблицах обратно в базу данных |
Сохранение данных из объекта в базу данных | Передача данных из объекта, который не входит в набор данных в базу данных с помощью метода TableAdapter DbDirect |
Сохранение данных с помощью методов DBDirect TableAdapter | Как использовать TableAdapter для отправки SQL-запросов непосредственно в базу данных |
Сохранение набора данных в формате XML | Сохранение набора данных в XML-документе |
Двухэтапные обновления
Обновление источника данных — это двухэтапный процесс. Первым шагом является обновление набора данных с новыми записями, измененными записями или удаленными записями. Если приложение никогда не отправляет эти изменения обратно в источник данных, завершите обновление.
Если вы отправляете изменения обратно в базу данных, необходимо выполнить второй шаг. Если вы не используете элементы управления с привязкой к данным, необходимо вручную вызвать метод того же адаптера TableAdapter (или адаптера данных), который использовался для заполнения набора данных. Однако можно также использовать различные адаптеры, например для перемещения данных из одного источника данных в другой или для обновления нескольких источников данных. Если вы не используете привязку данных и сохраняете изменения для связанных таблиц, необходимо вручную создать переменную автогенерированного TableAdapterManager
класса, а затем вызвать его UpdateAll
метод.
Набор данных содержит коллекции таблиц, которые содержат коллекции строк. Если вы планируете обновить базовый источник данных позже, при добавлении или удалении строк необходимо использовать методы в DataTable.DataRowCollection
свойстве. Эти методы выполняют отслеживание изменений, необходимое для обновления источника данных. При вызове коллекции RemoveAt
для свойства Rows удаление не будет передано обратно в базу данных.
Объединение наборов данных
Вы можете обновить содержимое набора данных, объединив его с другим набором данных. Это включает копирование содержимого исходного набора данных в вызывающий набор данных (называемый целевым набором данных). При слиянии наборов данных новые записи в исходном наборе данных добавляются в целевой набор данных. Кроме того, дополнительные столбцы в исходном наборе данных добавляются в целевой набор данных. Объединение наборов данных полезно при наличии локального набора данных и получения второго набора данных из другого приложения. Кроме того, это полезно при получении второй набор данных из компонента (например, веб-службы XML) или интеграции данных из нескольких наборов данных.
При слиянии наборов данных можно передать логический аргумент (preserveChanges
), который указывает методу Merge сохранить существующие изменения в целевом наборе данных. Так как наборы данных поддерживают несколько версий записей, важно помнить, что несколько версий записей объединяются. В следующей таблице показано, как объединяется запись в двух наборах данных:
DataRowVersion | Целевой набор данных | Исходный набор данных |
---|---|---|
Исходный текст | Джеймс Уилсон | Джеймс С. Уилсон |
Текущее | Джим Уилсон | Джеймс С. Уилсон |
Вызов метода Merge на предыдущей таблице с preserveChanges=false targetDataset.Merge(sourceDataset)
дает следующие данные:
DataRowVersion | Целевой набор данных | Исходный набор данных |
---|---|---|
Исходный текст | Джеймс С. Уилсон | Джеймс С. Уилсон |
Текущее | Джеймс С. Уилсон | Джеймс С. Уилсон |
Вызов метода Merge с preserveChanges = true targetDataset.Merge(sourceDataset, true)
приводит к следующим данным:
DataRowVersion | Целевой набор данных | Исходный набор данных |
---|---|---|
Исходный текст | Джеймс С. Уилсон | Джеймс С. Уилсон |
Текущее | Джим Уилсон | Джеймс С. Уилсон |
Осторожность
В сценарии preserveChanges = true
, если метод RejectChanges вызывается для записи в целевом наборе данных, он возвращает начальные данные из исходного набора данных. Это означает, что при попытке обновить исходный источник данных, используя целевой набор данных, может не удастся найти исходную строку для обновления. Нарушение параллелизма можно предотвратить, заполнив другой набор данных обновленными записями из источника данных, а затем выполнив слияние, чтобы предотвратить нарушение параллелизма. (Нарушение параллелизма возникает, когда другой пользователь изменяет запись в источнике данных после заполнения набора данных.)
Ограничения обновления
Чтобы внести изменения в существующую строку данных, добавить или обновить данные в отдельных столбцах. Если набор данных содержит ограничения (например, внешние ключи или ограничения, не допускающие значение NULL), возможно, запись может временно находиться в состоянии ошибки при обновлении. То есть, система может быть в состоянии ошибки после завершения обновления одного столбца, но прежде чем перейти к следующему.
Чтобы предотвратить нарушения преждевременных ограничений, можно временно приостановить ограничения обновления. Это служит двумя целями:
Это предотвращает возникновение ошибки после завершения обновления одного столбца и до начала обновления другого.
Он предотвращает возникновение определенных событий обновления (события, которые часто используются для проверки).
Замечание
В Windows Forms архитектура привязки данных, встроенная в таблицу данных, приостанавливает проверку ограничений, пока фокус не переместится с строки, и вам не нужно явно вызывать методы BeginEdit, EndEdit или CancelEdit.
Ограничения автоматически отключаются при Merge вызове метода в наборе данных. Когда слияние завершится, если имеются ограничения для набора данных, которые не могут быть активированы, выбрасывается исключение ConstraintException. В этой ситуации для свойства EnforceConstraints задано false,
, и необходимо устранить все нарушения ограничений до сброса свойства EnforceConstraints на true
.
После завершения обновления можно повторно выполнить проверку ограничений, которая также повторно создает события обновления и вызывает их.
Дополнительные сведения о приостановке событий см. в разделе "Отключение ограничений при заполнении набора данных".
Ошибки обновления набора данных
При обновлении записи в наборе данных возможна ошибка. Например, вы можете случайно записывать данные неправильного типа в столбец или данные, слишком длинные или данные, имеющие другую проблему целостности. Кроме того, у вас могут быть проверки, связанные с приложением, которые могут вызывать пользовательские ошибки во время любого этапа события обновления. Дополнительные сведения см. в разделе "Проверка данных в наборах данных".
Поддержание информации об изменениях
Сведения об изменениях в наборе данных поддерживаются двумя способами: путем перетаскивания строк, указывающих на то, что они изменились (RowState) и сохраняя несколько копий записи (DataRowVersion). С помощью этой информации процессы могут определить, что изменилось в наборе данных, и могут отправлять соответствующие обновления в источник данных.
Свойство RowState
RowState Свойство DataRow объекта — это значение, которое предоставляет сведения о состоянии определенной строки данных.
В следующей таблице приведены возможные значения перечисления DataRowState :
Значение DataRowState | Описание |
---|---|
Added | Строка добавлена в качестве элемента в DataRowCollection. (Строка в этом состоянии не имеет соответствующей исходной версии, так как она не существовала при вызове последнего AcceptChanges метода). |
Deleted | Строка была удалена с помощью DeleteDataRow объекта. |
Detached | Строка создана, но не является частью какого-либо DataRowCollection. DataRow Объект находится в этом состоянии сразу после его создания, прежде чем он был добавлен в коллекцию, и после удаления из коллекции. |
Modified | Значение столбца в строке изменилось каким-то образом. |
Unchanged | Строка не изменилась с тех пор, как AcceptChanges был вызван в последний раз. |
Перечисление DataRowVersion
Наборы данных поддерживают несколько версий записей. Поля DataRowVersion используются для извлечения значения, найденного в DataRow, с помощью свойства Item[] или метода GetChildRows объекта DataRow.
В следующей таблице приведены возможные значения перечисления DataRowVersion :
Значение DataRowVersion | Описание |
---|---|
Current | Текущая версия записи содержит все изменения, выполненные в записи с момента последнего AcceptChanges вызова. Если строка удалена, текущая версия отсутствует. |
Default | Значение записи по умолчанию, определенное схемой набора данных или источником данных. |
Original | Исходная версия записи — это копия записи, так как это было последнее время, когда изменения были зафиксированы в наборе данных. Практически это, как правило, версия записи, считываемая из источника данных. |
Proposed | Предлагаемая версия записи, которая доступна временно во время обновления, — это промежуток между вызовом метода BeginEdit и метода EndEdit. Как правило, вы обращаетесь к предлагаемой версии записи в обработчике для события, например RowChanging. Вызов CancelEdit метода изменяет изменения и удаляет предлагаемую версию строки данных. |
Исходные и текущие версии полезны при передаче сведений об обновлении в источник данных. Как правило, при отправке обновления в источник данных новая информация для базы данных находится в текущей версии записи. Сведения из исходной версии используются для поиска записи для обновления.
Например, в случае изменения первичного ключа записи необходимо найти правильную запись в источнике данных, чтобы обновить изменения. Если исходная версия не существует, то запись, скорее всего, будет добавлена в источник данных, что приведет не только к дополнительной нежелательной записи, но и в одной записи, которая является неточной и устаревшей. Две версии также используются в элементе управления параллелизмом. Вы можете сравнить исходную версию с записью в источнике данных, чтобы определить, изменилась ли запись после загрузки в набор данных.
Предлагаемая версия полезна, если необходимо выполнить проверку перед фиксацией изменений в наборе данных.
Даже если записи изменились, не всегда имеются исходные или текущие версии этой строки. При вставке новой строки в таблицу не существует исходной версии, только текущая версия. Аналогичным образом, при удалении строки путем вызова метода таблицы Delete
существует исходная версия, но текущая версия отсутствует.
Вы можете проверить, существует ли определенная версия записи, запрашивая метод строки HasVersion данных. Доступ к любой версии записи можно получить, передав DataRowVersion значение перечисления в качестве необязательного аргумента при запросе значения столбца.
Получение измененных записей
Это распространенная практика не обновлять каждую запись в наборе данных. Например, пользователь может работать с элементом управления Windows Forms DataGridView , отображающим множество записей. Однако пользователь может обновить только несколько записей, удалить его и вставить новый. Наборы данных и таблицы данных предоставляют метод (GetChanges
) для возврата только измененных строк.
Вы можете создавать подмножества измененных записей с помощью GetChanges
метода таблицы данных (GetChanges) или самого набора данных.GetChanges При вызове метода для таблицы данных возвращается копия таблицы только с измененными записями. Аналогичным образом, при вызове метода в наборе данных вы получите новый набор данных только с измененными записями в нем.
GetChanges
Сама по себе возвращает все измененные записи. В отличие от этого, передав требуемый DataRowState как параметр методу GetChanges
, вы можете указать, какое подмножество измененных записей вам нужно: только что добавленные записи, записи, помеченные для удаления, отсоединенные записи или измененные записи.
Получение подмножества измененных записей полезно при отправке записей в другой компонент для обработки. Вместо отправки всего набора данных можно сократить затраты на взаимодействие с другим компонентом, получив только записи, необходимые компоненту.
Фиксация изменений в наборе данных
По мере внесения изменений в набор данных, устанавливается свойство для измененных строк RowState. Исходные и текущие версии записей устанавливаются, поддерживаются и становятся доступными для вас свойством RowVersion . Метаданные, хранящиеся в свойствах этих измененных строк, необходимы для отправки правильных обновлений в источник данных.
Если изменения отражают текущее состояние источника данных, вам больше не нужно хранить эти сведения. Как правило, существует два раза, когда набор данных и его источник синхронизированы:
Сразу после загрузки данных в набор данных, например при чтении данных из источника.
После отправки изменений из набора данных в источник данных (но не раньше, так как вы потеряете сведения об изменениях, необходимых для отправки изменений в базу данных).
Вы можете зафиксировать ожидающие изменения в наборе данных, вызвав метод AcceptChanges. Как правило, AcceptChanges вызывается в следующее время:
После загрузки набора данных. При загрузке набора данных путем вызова метода TableAdapter
Fill
адаптер автоматически фиксирует изменения. Однако при загрузке набора данных путем объединения в него другого набора данных необходимо зафиксировать изменения вручную.После того как вы отправите изменения набора данных в другой процесс, например в веб-службу XML.
Осторожность
Фиксация изменения таким образом удаляет любые сведения об изменениях. Не фиксируйте изменения до тех пор, пока не завершите выполнение операций, требующих от приложения знать, какие изменения были внесены в набор данных.
Этот метод выполняет следующее:
Записывает Current версию записи в Original версию и перезаписывает исходную версию.
Удаляет любую строку, где свойство RowState установлено на Deleted.
Метод AcceptChanges доступен на трех уровнях. Его можно вызвать в объекте DataRow , чтобы зафиксировать изменения только для этой строки. Вы также можете вызвать его в объекте DataTable для фиксации всех строк в таблице. Наконец, можно вызвать метод для объекта DataSet, чтобы зафиксировать все ожидающие изменения во всех записях всех таблиц набора данных.
В следующей таблице описывается, какие изменения фиксируются в зависимости от того, на каком объекте вызывается метод:
Метод | Результат |
---|---|
System.Data.DataRow.AcceptChanges | Изменения фиксируются только в конкретной строке. |
System.Data.DataTable.AcceptChanges | Изменения фиксируются во всех строках в определенной таблице. |
System.Data.DataSet.AcceptChanges | Изменения фиксируются во всех строках во всех таблицах набора данных. |
Замечание
Если вы загружаете набор данных путем вызова метода TableAdapter Fill
, вам не нужно явно принимать изменения. По умолчанию Fill
метод вызывает AcceptChanges
метод после завершения заполнения таблицы данных.
Связанный метод RejectChangesотменяет эффект изменений путем копирования Original версии обратно в Current версию записей. Он также возвращает RowState каждой записи к Unchanged.
Проверка данных
Чтобы убедиться, что данные в приложении соответствуют требованиям передаваемых процессов, часто требуется добавить проверку. Это может привести к проверке правильности записи пользователя в форме, проверке данных, отправленных в приложение другим приложением, или даже проверке сведений, вычисляемых в компоненте, в пределах ограничений требований к источнику данных и приложению.
Данные можно проверить несколькими способами:
В бизнес-уровне добавьте код в приложение для проверки данных. Набор данных — это одно место, где это можно сделать. Набор данных предоставляет некоторые преимущества серверной валидации, например возможность валидировать изменения по мере изменения значений в столбцах и строках. Дополнительные сведения см. в разделе "Проверка данных в наборах данных".
На уровне презентации добавьте проверку в формы. Дополнительные сведения см. в разделе "Проверка ввода пользователей" в Windows Forms.
На серверной стороне данных, отправляя данные в источник данных (например, базу данных) и позволяя источнику данных принимать или отклонять данные. Если вы работаете с базой данных, которая имеет сложные средства для проверки данных и предоставления сведений об ошибках, это может быть практический подход, так как вы можете проверить данные независимо от того, откуда она исходит. Однако этот подход может не соответствовать требованиям к проверке, зависящим от приложения. Кроме того, валидация данных в источнике может привести к многочисленным обращениям к источнику данных, в зависимости от того, как ваше приложение способствует разрешению ошибок валидации, возникающих на стороне серверной части.
Это важно
При использовании команд данных со свойством CommandType, установленным в Text, тщательно проверяйте информацию, полученную от клиента, прежде чем передавать её в базу данных. Злоумышленники могут попытаться отправить (внедрить) измененные или дополнительные инструкции SQL, чтобы получить несанкционированный доступ или повредить базу данных. Прежде чем передавать входные данные пользователя в базу данных, всегда убедитесь, что информация действительна. Рекомендуется всегда использовать параметризованные запросы или хранимые процедуры, когда это возможно.
Передача обновлений в источник данных
После внесения изменений в набор данных можно передать изменения в источник данных. Чаще всего это делается путем вызова Update
метода TableAdapter (или адаптера данных). Метод выполняет циклы по каждой записи в таблице данных, определяет, какой тип обновления является обязательным (обновление, вставка или удаление), а затем выполняет соответствующую команду.
Как иллюстрация того, как выполняются обновления, предположим, что приложение использует набор данных, содержащий одну таблицу данных. Приложение получает две строки из базы данных. После получения таблица данных в памяти выглядит следующим образом:
(RowState) CustomerID Name Status
(Unchanged) c200 Robert Lyon Good
(Unchanged) c400 Nancy Buchanan Pending
Приложение изменяет статус Нэнси Бьюкенан на "Предпочитаемый". В результате этого изменения значение RowState свойства для этой строки изменяется с Unchanged на Modified. Значение RowState свойства для первой строки остается Unchanged. Теперь таблица данных выглядит следующим образом:
(RowState) CustomerID Name Status
(Unchanged) c200 Robert Lyon Good
(Modified) c400 Nancy Buchanan Preferred
Теперь приложение вызывает Update
метод для передачи набора данных в базу данных. Метод проверяет каждую строку в свою очередь. Для первой строки метод не передает инструкцию SQL в базу данных, так как эта строка не изменилась, так как изначально она была получена из базы данных.
Однако во второй строке Update
метод автоматически вызывает правильную команду данных и передает ее в базу данных. Конкретный синтаксис инструкции SQL зависит от диалекта SQL, поддерживаемого базовым хранилищем данных. Но следует отметить следующие общие признаки передаваемой инструкции SQL:
Передаваемая инструкция SQL — это
UPDATE
инструкция. Адаптер знает, что должен использовать операторUPDATE
, потому что значение свойства RowState равно Modified.Передаваемая инструкция SQL содержит предложение
WHERE
, указывающее, что инструкцияUPDATE
нацелена на строку, где находитсяCustomerID = 'c400'
. Эта часть инструкцииSELECT
отличает целевую строку от всех остальных, так какCustomerID
это первичный ключ целевой таблицы. Информация для условияWHERE
получена из исходной версии записи (DataRowVersion.Original
) в случае, если значения, необходимые для идентификации строкиWHERE
, изменились.Передаваемая инструкция SQL включает
SET
предложение, чтобы задать новые значения измененных столбцов.Замечание
Если для свойства TableAdapter
UpdateCommand
задано имя хранимой процедуры, адаптер не создает инструкцию SQL. Вместо этого он вызывает хранимую процедуру с переданными в неё соответствующими параметрами.
Передача параметров
Обычно используются параметры для передачи значений записей, которые будут обновляться в базе данных. Когда метод TableAdapter Update
запускает инструкцию UPDATE
, необходимо заполнить значения параметров. Он получает эти значения из коллекции Parameters
для соответствующей команды данных — в данном случае объекта UpdateCommand
в TableAdapter.
Если вы использовали средства Visual Studio для создания адаптера данных, UpdateCommand
объект содержит коллекцию параметров, соответствующих каждому заполнителю параметров в инструкции.
Свойство System.Data.SqlClient.SqlParameter.SourceColumn каждого параметра указывает на столбец в таблице данных. Например, свойство SourceColumn
для параметров au_id
и Original_au_id
установлено на тот столбец в таблице данных, который содержит идентификатор автора. Когда запускается метод адаптера Update
, он считывает столбец с идентификатором автора из обновляемой записи и заполняет инструкцию значениями.
UPDATE
В инструкции необходимо указать как новые значения (те, которые будут записаны в запись), так и старые значения (чтобы запись была расположена в базе данных). Таким образом, существует два параметра для каждого значения: один для SET
предложения и другой для WHERE
предложения. Оба параметра считывают данные из обновляемой записи, но они получают разные версии значения столбца на основе свойства параметра SourceVersion . Параметр для предложения SET
получает текущую версию, а параметр для предложения WHERE
получает исходную версию.
Замечание
Вы также можете самостоятельно задать значения в коллекции в Parameters
коде, что обычно делается в обработчике событий для события RowChanging адаптера данных.