Глава 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();