using System;
using System.Data;
namespace mergeTest
{
class Class1
{
static void Main(string[] args)
{
// Создается объект DataSet.
DataSet ds = new DataSet("myDataSet");
// Создается таблица.
DataTable t = new DataTable("Items");
// Столбцы таблицы – это особые объекты.
// Имя первого столбца – id, тип значения – System.Int32.
DataColumn c1 = new DataColumn("id", Type.GetType("System.Int32"));
c1.AutoIncrement=true;
// Имя второго столбца – Item, тип значения – System.Int32.
DataColumn c2 = new DataColumn("Item", Type.GetType("System.Int32"));
// Сборка объекта DataSet:
// Добавляются объекты-столбцы...
t.Columns.Add(c1);
t.Columns.Add(c2);
// А вот массив столбцов (здесь он из одного элемента)
// для организации первичного ключа (множества первичных ключей).
DataColumn[] keyCol= new DataColumn[1];
// И вот, собственно, как в таблице задается множество первичных ключей.
keyCol[0]= c1;
// Свойству объекта t передается массив, содержащий столбцы, которые
// формируемая таблица t будет воспринимать как первичные ключи.
t.PrimaryKey=keyCol;
// А что с этими ключами будет t делать? А это нас в данный момент
// не касается. Очевидно, что методы, которые обеспечивают контроль
// над информацией в соответствии со значениями ключей, уже где-то
// "зашиты" в классе DataTable. Как и когда они будут выполняться –
// не наше дело. Наше дело – указать на столбцы, которые для данной
// таблицы будут ключевыми. Что мы и сделали.
// Таблица подсоединяется к объекту ds – представителю класса DataSet.
ds.Tables.Add(t);
DataRow r;
// В таблицу, которая уже присоединена к
// объекту ds DataSet, добавляется 10 rows.
for(int i = 0; i <10;i++)
{
r=t.NewRow();
r["Item"]= i;
t.Rows.Add(r);
}
// Принять изменения.
// Так производится обновление DataSet'а.
// Сведения о новых изменениях и добавлениях будут фиксироваться
// вплоть до нового обновления.
ds.AcceptChanges();
PrintValues(ds, "Original values");
// Изменение значения в первых двух строках.
t.Rows[0]["Item"]= 50;
t.Rows[1]["Item"]= 111;
t.Rows[2]["Item"]= 111;
// Добавление еще одной строки.
// Судя по всему, значение первого столбца устанавливается автоматически.
// Это ключевое поле со значением порядкового номера строки.
r=t.NewRow();
r["Item"]=74;
t.Rows.Add(r);
// Объявляем ссылку для создания временного DataSet.
DataSet xSet;
// ДЕКЛАРАЦИЯ О НАМЕРЕНИЯХ КОНТРОЛЯ ЗА КОРРЕКТНОСТЬЮ ЗНАЧЕНИЙ СТРОКИ.
// Вот так добавляется свойство, содержащее строку для описания
// ошибки в значении. Наш DataSet содержит одну строку с описанием.
// Это всего лишь указание на то обстоятельство, что МЫ САМИ
// обязались осуществлять
// некоторую деятельность по проверке чего-либо. Чтобы не забыть,
// в чем проблема,
// описание возможной ошибки (в свободной форме!) добавляем
// в свойства строки,
// значения которой требуют проверки.
t.Rows[0].RowError= "over 100 (ЙЦУКЕН!)";
t.Rows[1].RowError= "over 100 (Stupid ERROR!)";
t.Rows[2].RowError= "over 100 (Ну и дела!)";
// Но одно дело – декларировать намерения, а другое – осуществлять
// контроль.
// Проблема проверки корректности значения – наша личная проблема.
// Однако о наших намерениях контроля за значениями становится
// известно объекту – представителю DataSet!
PrintValues(ds, "Modified and New Values");
// Мы вроде бы согласились проводить контроль значений.
// Даже декларировали некий принцип проверки.
// Однако ничего само собой не происходит.
// Так вот,
//
// ЕСЛИ В ТАБЛИЦУ БЫЛИ ДОБАВЛЕНЫ СТРОКИ ИЛИ ИЗМЕНЕНЫ ЗНАЧЕНИЯ СТРОК
// И
// МЫ ОБЯЗАЛИСЬ КОНТРОЛИРОВАТЬ ЗНАЧЕНИЯ СТРОК В ТАБЛИЦЕ,
//
// то самое время организовать эту проверку...
// Критерий правильности значений, естественно, наш!
// Алгоритмы проверки – тоже НАШИ!
// Единственное, чем нам может помочь ADO .NET, – это выделить
// подмножество строк таблицы,
// которые были добавлены или модифицированы со времени последнего
// обновления нашего объекта - представителя DataSet'а,
if(ds.HasChanges(DataRowState.Modified | DataRowState.Added)& ds.HasErrors)
{
// И для этого мы воспользуемся методом, который позволяет обеспечить
// выделение подмножества добавленных и
// модифицированных строк в новый объект DataSet'а.
// Use GetChanges to extract subset.
xSet = ds.GetChanges(DataRowState.Modified|DataRowState.Added);
PrintValues(xSet, "Subset values");
// Insert code to reconcile errors. In this case, we'll reject changes.
// Вот, собственно, код проверки. Все делается своими руками.
foreach(DataTable xTable in xSet.Tables)
{
if (xTable.HasErrors)
{
foreach(DataRow xRow in xTable.Rows)
{
// Выделенное подмножество проверяем на наличие
// ошибочного значения (для нас все, что больше 100, –
// уже ошибка!)
Console.Write(xRow["Item"] + " ");
if((int)xRow["Item",DataRowVersion.Current ]> 100)
{
// Находим ошибку в строке, сообщаем о ней,
Console.WriteLine("Error! – " + xRow.RowError);
// Возвращаем старое значение...
xRow.RejectChanges();
// Отменяем значение свойства - уведомителя о возможных
// ошибках для данной строки...
xRow.ClearErrors();
}
else
Console.WriteLine("OK.");
}
}
}
PrintValues(xSet, "Reconciled subset values");
// Сливаем измененные и откорректированные строки в основной
// объект – DataSet
// Merge changes back to first DataSet.
ds.Merge(xSet);
PrintValues(ds, "Merged Values");
}
}
// А это всего лишь вывод содержимого DataSet'а.
private static void PrintValues(DataSet ds, string label)
{
Console.WriteLine("\n" + label);
foreach(DataTable t in ds.Tables)
{
Console.WriteLine("TableName: " + t.TableName);
foreach(DataRow r in t.Rows)
{
foreach(DataColumn c in t.Columns)
{
Console.Write("\t " + r[c] );
}
Console.WriteLine();
}
}
}
}
} |
Листинг 18.8. |
| Закрыть окно |