Глава 4. Работа с DataTable / DataSet

DataTable

Объект DataTable является центральным объектом библиотеки ADO.NET. Другие объекты, использующие объект DataTable, включают также DataSet и DataView. При доступе к объектам DataTable следует учитывать их зависимость от регистра знаков при определенных условиях. Например, если один объект DataTable носит имя mydatatable, а другой — Mydatatable, то строка, используемая для поиска одной из таблиц, считается зависимой от регистра букв. Однако если mydatatable существует, а Mydatatable нет, строка поиска считается нечувствительной к регистру. Набор DataSet может содержать два объекта DataTable, имеющих одно и то же значение свойства TableName, но разные значения свойства Namespace.

Если объект DataTable создается программно, необходимо сначала определить его схему, добавив объекты DataColumn в коллекцию DataColumnCollection (доступна через свойство Columns).

Чтобы добавить строки в объект DataTable, необходимо сначала вернуть новый объект DataRow с помощью метода NewRow. Метод NewRow возвращает строку со схемой объекта DataTable, согласно тому, как она определена в коллекции DataColumnCollection таблицы. Максимальное количество строк, которое может храниться в объекте DataTable, равно 16 777 216.

Объект DataTable содержит также коллекцию объектов Constraint, используемых для обеспечения целостности данных.

Существует много событий DataTable, которые могут использоваться для определения времени внесения изменений в таблицу. К этим событиям относятся RowChanged, RowChanging, RowDeleting и RowDeleted.

Дополнительные сведения о событиях, которые могут использоваться с объектом DataTable, см. в разделе Обработка событий DataTable (ADO.NET).

При создании экземпляра класса DataTable некоторым свойствам чтения и записи задаются начальные значения. Список этих значений см. в разделе, посвященном конструктору DataTable.DataTable.

Объект DataTable, который представляет одну таблицу находящихся в памяти реляционных данных, может создаваться и использоваться независимо или использоваться другими объектами .NET Framework, чаще всего как член DataSet. Объект DataTable можно создать, используя соответствующий конструктор для DataTable. Этот объект можно добавить в DataSet при помощи метода Add, чтобы добавить его в коллекцию Tables объекта DataTable. Можно также создать объекты DataTable в DataSet при помощи методов Fill или FillSchema объекта DataAdapter либо из стандартной или выводимой схемы XML с использованием методов ReadXml, ReadXmlSchema или InferXmlSchema объекта DataSet. Следует отметить, что после добавления объекта DataTable как члена коллекции Tables объекта DataSet его нельзя добавить в коллекцию таблиц какого-либо другого объекта DataSet. При первом создании объекта DataTable у него нет схемы (т. е. структуры). Для определения схемы таблицы необходимо создать и добавить объекты DataColumn в коллекцию Columns таблицы. Можно также определить столбец первичного ключа для таблицы, а также создать и добавить объекты Constraint в коллекцию Constraints таблицы. После определения схемы для таблицы DataTable можно добавить в таблицу строки данных, добавив объекты DataRow в коллекцию Rows таблицы. Не требуется предоставлять значение для свойства TableName при создании объекта DataTable; свойство можно задать в любое время либо оставить его пустым. Однако при добавлении таблицы без значения TableName в объект DataSet таблице присваивается имя по умолчанию TableN с увеличивающимся каждый раз значением N на единицу, начиная с имени Table для Table0.

//создается экземпляр объекта DataTable, которому присваивается имя «Customers»
DataTable workTable = new DataTable("Customers");

// создается экземпляр таблицы DataTable добавлением его в коллекцию Tables объекта DataSet.
DataSet customers = new DataSet();
DataTable customersTable = customers.Tables.Add("CustomersTable");

DataTable содержит коллекцию объектов DataColumn, на которые ссылается свойство Columns таблицы. Эта коллекция столбцов наряду с ограничениями определяет схему, или структуру, таблицы. Создаются объекты DataColumn в таблице, используя конструктор DataColumn или вызывая метод Add свойства Columns таблицы, которая является объектом DataColumnCollection. Метод Add принимает необязательные аргументы ColumnName, DataType и Expression и создает новый DataColumn как член коллекции. Он также принимает существующий объект DataColumn и добавляет его в коллекцию, а также возвращает ссылку на добавленный DataColumn, если требуется. Так как объекты DataTable не являются специфичными для какого-либо источника данных, типы .NET Framework используются при задании типов данных для DataColumn.

DataTable workTable = new DataTable("Customers");

DataColumn workCol = workTable.Columns.Add("CustID", typeof(Int32));
workCol.AllowDBNull = false;
workCol.Unique = true;

//добавляются четыре столбца к объекту DataTable
workTable.Columns.Add("CustLName", typeof(String));
workTable.Columns.Add("CustFName", typeof(String));
workTable.Columns.Add("Purchases", typeof(Double));

Обратите внимание, что в данном примере свойства для столбца CustID установлены так, что не позволяют значениям DBNull и значениям ограничений быть уникальными. Но если столбец CustID определяется как столбец первичного ключа таблицы, свойство AllowDBNull будет автоматически установлено в false, а свойство Unique будет автоматически установлено в true.

После создания объекта DataTable и определения его структуры с использованием столбцов и ограничений к созданной таблице можно добавлять новые строки данных. Чтобы добавить новую строку, объявите новую переменную типа DataRow. При вызове метода NewRow будет возвращен новый объект DataRow. Затем объект DataTable создает объект DataRow на основе структуры таблицы, определенной в DataColumnCollection.

//создаем новую строку путем вызова метода NewRow
DataRow workRow = workTable.NewRow();

//обращение к полю таблицы по имени и индексу
workRow["CustLName"] = "Smith";
workRow[1] = "Smith";

//После вставки данных в новую строку для добавления строки в объект DataRowCollection 
//применяется метод Add
workTable.Rows.Add(workRow);

//для добавления новой строки путем передачи массива значений с типом Object
workTable.Rows.Add(new Object[] {1, "Smith"});

Передача массива значений с типом Object в метод Add приводит к созданию новой строки в таблице и заданию значений столбцов этой строки, соответствующих значениям в массиве объектов. Обратите внимание, что значения в массиве сопоставляются со столбцами последовательно, с учетом порядка этих столбцов в таблице.

Чтобы добавить 10 строк к вновь созданной таблице Customers.

DataRow workRow;

for (int i = 0; i <= 9; i++) 
{
  workRow = workTable.NewRow();
  workRow[0] = i;
  workRow[1] = "CustName" + i.ToString();
  workTable.Rows.Add(workRow);
}

Ограничения позволяют принудительно поддерживать целостность данных DataTable и представляет собой автоматическое правило, применяемое к столбцу или связанным столбцам и определяющее порядок действий при каком-либо изменении содержимого строки. Ограничения применяются, если свойство EnforceConstraints коллекции DataSet имеет значение true. В ADO.NET имеется два типа ограничений: ForeignKeyConstraint и UniqueConstraint. По умолчанию оба ограничения создаются автоматически при установке связи между двумя или несколькими таблицами путем добавления отношения DataRelation к коллекции DataSet. Однако такое поведение можно отменить, указав параметр createConstraints = false при создании связи.

Ограничение ForeignKeyConstraint

Ограничение ForeignKeyConstraint применяет правила распространения обновлений и удалений в связанных таблицах. Например, если обновлено или удалено значение строки одной таблицы, и то же самое значение используется в одной или нескольких связанных таблицах, ForeignKeyConstraint определяет, что произойдет в связанных таблицах. Свойства DeleteRule и UpdateRule ограничения ForeignKeyConstraint задают действие, которое должно быть выполнено, когда пользователь пытается удалить или обновить строку в связанной таблице. В следующей таблице приведены настройки, доступные для свойств DeleteRule и UpdateRule ограничения ForeignKeyConstraint.

Установка правил Описание
Cascade Удалить или обновить связанные строки.
SetNull Присвоить столбцам в связанных строках значение DBNull.
SetDefault Присвоить столбцам в связанных строках значение по умолчанию.
None Не выполнять никаких действий в связанных строках. Это настройка по умолчанию.

ForeignKeyConstraint может ограничивать или распространять изменения на связанные столбцы. В зависимости от свойств, заданных для ограничения ForeignKeyConstraint столбца, при значении свойства EnforceConstraints для DataSet, равном true, определенные операции в родительских строках приведут к возникновению исключения. Например, если свойство DeleteRule ограничения ForeignKeyConstraint имеет значение None, родительскую строку нельзя удалять, если у нее имеются дочерние строки.

Можно создать ограничение внешнего ключа между отдельными столбцами или массивом столбцов с помощью конструктора ForeignKeyConstraint. Передайте объект ForeignKeyConstraint методу Add свойства таблицы Constraints, которое представляет собой объект ConstraintCollection. Для создания ограничения ForeignKeyConstraint можно также передать аргументы конструктора одному из нескольких перегруженных методов Add коллекции ConstraintCollection. При создании ограничения ForeignKeyConstraint можно передать конструктору значения DeleteRule и UpdateRule в качестве аргументов или задать их в виде свойств, как показано в следующем примере (где значение DeleteRule равно None).

ForeignKeyConstraint custOrderFK = new ForeignKeyConstraint("CustOrderFK",
  custDS.Tables["CustTable"].Columns["CustomerID"], 
  custDS.Tables["OrdersTable"].Columns["CustomerID"]);
custOrderFK.DeleteRule = Rule.None;  
// Cannot delete a customer value that has associated existing orders.
custDS.Tables["OrdersTable"].Constraints.Add(custOrderFK);
Свойство AcceptRejectRule

Изменения строк можно принять, используя метод AcceptChanges, или отменить с помощью метода RejectChanges для DataSet, DataTable или DataRow. Если DataSet содержит ограничение ForeignKeyConstraints, вызов методов AcceptChanges и RejectChanges применяет свойство AcceptRejectRule. Свойство AcceptRejectRule ограничения ForeignKeyConstraint определяет, какие действия следует предпринять в дочерних строках, если в родительской строке вызывается метод AcceptChanges или RejectChanges. В следующей таблице перечислены доступные настройки AcceptRejectRule.

Ограничение UniqueConstraint

Объект UniqueConstraint, назначаемый или отдельному столбцу, или массиву столбцов в наборе данных DataTable, обеспечивает уникальность всех данных заданного столбца или столбцов для одной строки. Можно создать ограничение уникальности для столбца или массива столбцов с помощью конструктора UniqueConstraint. Передайте объект UniqueConstraint методу Add свойства таблицы Constraints, которое представляет собой коллекцию ConstraintCollection. Для создания ограничения UniqueConstraint можно также передать аргументы конструктора одному из нескольких перегруженных методов Add коллекции ConstraintCollection. При создании ограничения UniqueConstraint для одного или нескольких столбцов можно по желанию указать, является ли этот столбец или группа столбцов первичным ключом.

Можно также создать ограничение уникальности для столбца, присвоив его свойству Unique значение true. Либо, присвоив свойству Unique одного столбца значение false, можно удалить любое существующее ограничение уникальности. При определении столбца или группы столбцов в качестве первичного ключа таблицы автоматически создается ограничение уникальности для заданного столбца или группы столбцов. Если удалить столбец из свойства PrimaryKey для DataTable, ограничение UniqueConstraint удаляется. В следующем примере создается ограничение UniqueConstraint для двух столбцов DataTable.

DataTable custTable = custDS.Tables["Customers"];
UniqueConstraint custUnique = new UniqueConstraint(new DataColumn[] 
    {custTable.Columns["CustomerID"], 
    custTable.Columns["CompanyName"]});
custDS.Tables["Customers"].Constraints.Add(custUnique);

1. Пример

В следующем примере демонстрируется, как создавать обработчики событий для событий RowChanged, RowChanging, RowDeleted, RowDeleting, ColumnChanged, ColumnChanging, TableNewRow, TableCleared и TableClearing. Каждый обработчик события при возникновении события отображает выводимые данные в консольном окне.

// Put the next line into the Declarations section.
private System.Data.DataSet dataSet;

private void MakeDataTables()
{
    // Run all of the functions. 
    MakeParentTable();
    MakeChildTable();
    MakeDataRelation();
    BindToDataGrid();
}

private void MakeParentTable()
{
    // Create a new DataTable.
    System.Data.DataTable table = new DataTable("ParentTable");
    // Declare variables for DataColumn and DataRow objects.
    DataColumn column;
    DataRow row;

    // Create new DataColumn, set DataType, 
    // ColumnName and add to DataTable.    
    column = new DataColumn();
    column.DataType = System.Type.GetType("System.Int32");
    column.ColumnName = "id";
    column.ReadOnly = true;
    column.Unique = true;
    // Add the Column to the DataColumnCollection.
    table.Columns.Add(column);

    // Create second column.
    column = new DataColumn();
    column.DataType = System.Type.GetType("System.String");
    column.ColumnName = "ParentItem";
    column.AutoIncrement = false;
    column.Caption = "ParentItem";
    column.ReadOnly = false;
    column.Unique = false;
    // Add the column to the table.
    table.Columns.Add(column);

    // Make the ID column the primary key column.
    DataColumn[] PrimaryKeyColumns = new DataColumn[1];
    PrimaryKeyColumns[0] = table.Columns["id"];
    table.PrimaryKey = PrimaryKeyColumns;

    // Instantiate the DataSet variable.
    dataSet = new DataSet();
    // Add the new DataTable to the DataSet.
    dataSet.Tables.Add(table);

    // Create three new DataRow objects and add 
    // them to the DataTable
    for (int i = 0; i<= 2; i++)
    {
        row = table.NewRow();
        row["id"] = i;
        row["ParentItem"] = "ParentItem " + i;
        table.Rows.Add(row);
    }
}

private void MakeChildTable()
{
    // Create a new DataTable.
    DataTable table = new DataTable("childTable");
    DataColumn column;
    DataRow row;

    // Create first column and add to the DataTable.
    column = new DataColumn();
    column.DataType= System.Type.GetType("System.Int32");
    column.ColumnName = "ChildID";
    column.AutoIncrement = true;
    column.Caption = "ID";
    column.ReadOnly = true;
    column.Unique = true;

    // Add the column to the DataColumnCollection.
    table.Columns.Add(column);

    // Create second column.
    column = new DataColumn();
    column.DataType= System.Type.GetType("System.String");
    column.ColumnName = "ChildItem";
    column.AutoIncrement = false;
    column.Caption = "ChildItem";
    column.ReadOnly = false;
    column.Unique = false;
    table.Columns.Add(column);

    // Create third column.
    column = new DataColumn();
    column.DataType= System.Type.GetType("System.Int32");
    column.ColumnName = "ParentID";
    column.AutoIncrement = false;
    column.Caption = "ParentID";
    column.ReadOnly = false;
    column.Unique = false;
    table.Columns.Add(column);

    dataSet.Tables.Add(table);

    // Create three sets of DataRow objects, 
    // five rows each, and add to DataTable.
    for(int i = 0; i <= 4; i ++)
    {
        row = table.NewRow();
        row["childID"] = i;
        row["ChildItem"] = "Item " + i;
        row["ParentID"] = 0 ;
        table.Rows.Add(row);
    }
    for(int i = 0; i <= 4; i ++)
    {
        row = table.NewRow();
        row["childID"] = i + 5;
        row["ChildItem"] = "Item " + i;
        row["ParentID"] = 1 ;
        table.Rows.Add(row);
    }
    for(int i = 0; i <= 4; i ++)
    {
        row = table.NewRow();
        row["childID"] = i + 10;
        row["ChildItem"] = "Item " + i;
        row["ParentID"] = 2 ;
        table.Rows.Add(row);
    }
}

private void MakeDataRelation()
{
    // DataRelation requires two DataColumn 
    // (parent and child) and a name.
    DataColumn parentColumn = 
        dataSet.Tables["ParentTable"].Columns["id"];
    DataColumn childColumn = 
        dataSet.Tables["ChildTable"].Columns["ParentID"];
    DataRelation relation = new 
        DataRelation("parent2Child", parentColumn, childColumn);
    dataSet.Tables["ChildTable"].ParentRelations.Add(relation);
}

private void BindToDataGrid()
{
    // Instruct the DataGrid to bind to the DataSet, with the 
    // ParentTable as the topmost DataTable.
    dataGrid1.SetDataBinding(dataSet,"ParentTable");
}

2. Пример

//Create DataTable 
DataTable dt= new DataTable();
dt.Columns.AddRange(New DataColumn[]
{
   new DataColumn("ID",typeOf(System.Int32)),
   new DataColumn("Name",typeOf(System.String))

});

//Fill with data

dt.Rows.Add(new Object[]{1,"Test1"});
dt.Rows.Add(new Object[]{2,"Test2"});

//Now  Query DataTable with linq
//To work with linq it should required our source implement IEnumerable interface.
//But DataTable not Implement IEnumerable interface
//So we call DataTable Extension method  i.e AsEnumerable() this will return EnumerableRowCollection<DataRow>


// Now Query DataTable to find Row whoes ID=1

DataRow drow = dt.AsEnumerable().Where(p=>p.Field<Int32>(0)==1).FirstOrDefault();

results matching ""

    No results matching ""