Сохранение данных обратно в базу данных в приложениях платформа .NET Framework
Примечание.
Наборы данных и связанные классы являются устаревшими технологиями платформа .NET Framework с начала 2000-х годов, которые позволяют приложениям работать с данными в памяти во время отключения приложений от базы данных. Технологии особенно полезны для приложений, которые позволяют пользователям изменять данные и сохранять изменения обратно в базу данных. Хотя наборы данных оказались очень успешными, мы рекомендуем новым приложениям .NET использовать Entity Framework Core. Entity Framework предоставляет более естественный способ работы с табличными данными в виде объектных моделей, и он имеет более простой интерфейс программирования.
Набор данных — это копия данных в памяти. При изменении этих данных рекомендуется сохранить эти изменения обратно в базу данных. Это можно сделать одним из трех способов:
Вызов одного из
Update
методов TableAdapterВызов одного из
DBDirect
методов TableAdapterUpdateAll
Вызов метода в TableAdapterManager, который Visual Studio создает для вас, когда набор данных содержит таблицы, связанные с другими таблицами в наборе данных.
При привязке таблиц наборов данных к элементам управления на странице Windows Form или XAML архитектура привязки данных выполняет всю работу.
Если вы знакомы с TableAdapters, вы можете перейти непосредственно к одному из следующих разделов:
Раздел | Описание |
---|---|
Вставка новых записей в базу данных | Как выполнять обновления и вставки с помощью объектов TableAdapters или Command |
Обновление данных с помощью адаптера таблицы | Как выполнять обновления с помощью TableAdapters |
Иерархическое обновление | Как выполнять обновления из набора данных с двумя или более связанными таблицами |
Обработка исключения параллельности | Обработка исключений при попытке двух пользователей одновременно изменить одни и те же данные в базе данных |
Практическое руководство. Сохранение данных с помощью транзакции | Как сохранить данные в транзакции с помощью системы. Пространство имен транзакций и объект TransactionScope |
Сохранение данных в транзакции | Пошаговое руководство по созданию приложения Windows Forms для демонстрации сохранения данных в базе данных внутри транзакции |
Сохранение данных в базе данных (несколько таблиц) | Изменение записей и сохранение изменений в нескольких таблицах обратно в базу данных |
Сохранение данных из объекта в базе данных | Передача данных из объекта, который не входит в набор данных в базу данных с помощью метода TableAdapter DbDirect |
Сохранение данных с помощью методов DBDirect адаптера таблицы | Как использовать TableAdapter для отправки SQL-запросов непосредственно в базу данных |
Сохранение набора данных в формате XML | Сохранение набора данных в XML-документе |
Двухэтапные обновления
Обновление источника данных — это двухэтапный процесс. Первым шагом является обновление набора данных с новыми записями, измененными записями или удаленными записями. Если приложение никогда не отправляет эти изменения обратно в источник данных, завершите обновление.
Если вы отправляете изменения обратно в базу данных, необходимо выполнить второй шаг. Если вы не используете элементы управления с привязкой к данным, необходимо вручную вызвать Update
метод того же адаптера tableAdapter (или адаптера данных), который использовался для заполнения набора данных. Однако можно также использовать различные адаптеры, например для перемещения данных из одного источника данных в другой или для обновления нескольких источников данных. Если вы не используете привязку данных и сохраняете изменения для связанных таблиц, необходимо вручную создать переменную автогенерированного TableAdapterManager
класса, а затем вызвать его UpdateAll
метод.
Набор данных содержит коллекции таблиц, которые содержат коллекции строк. Если вы планируете обновить базовый источник данных позже, при добавлении или удалении строк необходимо использовать методы в DataTable.DataRowCollection
свойстве. Эти методы выполняют отслеживание изменений, необходимое для обновления источника данных. При вызове RemoveAt
коллекции в свойстве Rows удаление не будет передано обратно в базу данных.
Объединение наборов данных
Вы можете обновить содержимое набора данных, объединив его с другим набором данных. Это включает копирование содержимого исходного набора данных в вызывающий набор данных (называемый целевым набором данных). При слиянии наборов данных новые записи в исходном наборе данных добавляются в целевой набор данных. Кроме того, дополнительные столбцы в исходном наборе данных добавляются в целевой набор данных. Объединение наборов данных полезно при наличии локального набора данных и получения второго набора данных из другого приложения. Кроме того, при получении второго набора данных из компонента, например веб-службы XML, или при необходимости интегрировать данные из нескольких наборов данных.
При слиянии наборов данных можно передать логический аргумент (preserveChanges
), который указывает Merge методу сохранить существующие изменения в целевом наборе данных. Так как наборы данных поддерживают несколько версий записей, важно помнить, что несколько версий записей объединяются. В следующей таблице показано, как объединяется запись в двух наборах данных:
DataRowVersion | Целевой набор данных | Исходный набор данных |
---|---|---|
Исходная | Джеймс Уилсон | Джеймс С. Уилсон |
Текущие | Джим Уилсон | Джеймс С. Уилсон |
Вызов метода в предыдущей Merge таблице с preserveChanges=false targetDataset.Merge(sourceDataset)
результатами следующих данных:
DataRowVersion | Целевой набор данных | Исходный набор данных |
---|---|---|
Исходная | Джеймс С. Уилсон | Джеймс С. Уилсон |
Текущие | Джеймс С. Уилсон | Джеймс С. Уилсон |
Вызов метода с preserveChanges = true targetDataset.Merge(sourceDataset, true)
результатами Merge в следующих данных:
DataRowVersion | Целевой набор данных | Исходный набор данных |
---|---|---|
Исходная | Джеймс С. Уилсон | Джеймс С. Уилсон |
Текущие | Джим Уилсон | Джеймс С. Уилсон |
Внимание
preserveChanges = true
В сценарии, если RejectChanges метод вызывается в записи в целевом наборе данных, он возвращает исходные данные из исходного набора данных. Это означает, что при попытке обновить исходный источник данных с целевым набором данных может не быть в состоянии найти исходную строку для обновления. Нарушение параллелизма можно предотвратить, заполнив другой набор данных обновленными записями из источника данных, а затем выполнив слияние, чтобы предотвратить нарушение параллелизма. (Нарушение параллелизма возникает, когда другой пользователь изменяет запись в источнике данных после заполнения набора данных.)
Ограничения обновления
Чтобы внести изменения в существующую строку данных, добавить или обновить данные в отдельных столбцах. Если набор данных содержит ограничения (например, внешние ключи или ограничения, не допускающие значение NULL), возможно, запись может временно находиться в состоянии ошибки при обновлении. То есть это может быть в состоянии ошибки после завершения обновления одного столбца, но прежде чем перейти к следующему.
Чтобы предотвратить нарушения преждевременных ограничений, можно временно приостановить ограничения обновления. Это служит двумя целями:
Это предотвращает возникновение ошибки после завершения обновления одного столбца, но не начало обновления другого.
Он предотвращает возникновение определенных событий обновления (события, которые часто используются для проверки).
Примечание.
В Windows Forms архитектура привязки данных, встроенная в datagrid, приостанавливает проверку ограничений, пока фокус не перейдет из строки, и вам не нужно явно вызывать BeginEditEndEditметоды или CancelEdit методы.
Ограничения автоматически отключаются при Merge вызове метода в наборе данных. Когда слияние завершится, при наличии ограничений для набора данных, который не может быть включен, ConstraintException создается исключение. В этой ситуации EnforceConstraints для свойства задано false,
значение, и перед сбросом свойства true
необходимо устранить все нарушения ограниченийEnforceConstraints.
После завершения обновления можно повторно выполнить проверку ограничений, которая также повторно создает события обновления и вызывает их.
Дополнительные сведения о приостановке событий см. в разделе "Отключение ограничений при заполнении набора данных".
Ошибки обновления набора данных
При обновлении записи в наборе данных возможна ошибка. Например, вы можете случайно записывать данные неправильного типа в столбец или данные, слишком длинные или данные, имеющие другую проблему целостности. Кроме того, у вас могут быть проверки, связанные с приложением, которые могут вызывать пользовательские ошибки во время любого этапа события обновления. Дополнительные сведения см. в разделе "Проверка данных в наборах данных".
Обслуживание сведений об изменениях
Сведения об изменениях в наборе данных поддерживаются двумя способами: путем перетаскивания строк, указывающих на то, что они изменились (RowState) и сохраняя несколько копий записи (DataRowVersion). С помощью этой информации процессы могут определить, что изменилось в наборе данных, и могут отправлять соответствующие обновления в источник данных.
Свойство RowState
RowState Свойство DataRow объекта — это значение, которое предоставляет сведения о состоянии определенной строки данных.
В следующей таблице приведены возможные значения перечисления DataRowState :
Значение DataRowState | Description |
---|---|
Added | Строка добавлена в качестве элемента DataRowCollection. (Строка в этом состоянии не имеет соответствующей исходной версии, так как она не существовала при вызове последнего AcceptChanges метода). |
Deleted | Строка была удалена с помощью Delete DataRow объекта. |
Detached | Строка создана, но не является частью любой DataRowCollection. DataRow Объект находится в этом состоянии сразу после его создания, прежде чем он был добавлен в коллекцию, и после удаления из коллекции. |
Modified | Значение столбца в строке изменилось каким-то образом. |
Unchanged | Строка не изменилась с момента AcceptChanges последнего вызова. |
DataRowVersion - перечисление
Наборы данных поддерживают несколько версий записей. Поля DataRowVersion используются при получении значения, найденного в DataRow Item[] свойстве или GetChildRows методе DataRow объекта.
В следующей таблице приведены возможные значения перечисления DataRowVersion :
Значение DataRowVersion | Description |
---|---|
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.
Внимание
Фиксация изменения таким образом удаляет любые сведения об изменениях. Не фиксируйте изменения до тех пор, пока не завершите выполнение операций, требующих от приложения знать, какие изменения были внесены в набор данных.
Этот метод выполняет следующее:
Записывает версию записи в ее Original версию и перезаписывает Current исходную версию.
Удаляет любую строку, 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
это первичный ключ целевой таблицы. Сведения о предложении являются производными от исходной версии записи (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 данных.