После получения данных из базы данных через SqlDataAdapter в DataSet мы можем локально работать с этими данными вне зависимости от наличия подключения. Более того если нам даже и не надо использовать никакую базу данных, но при этом мы хотим иметь удобный функционал для работы с данными в виде наборов таблиц, то мы также можем воспользоваться классом DataSet.
Объект DataSet содержит таблицы, которые представлены типом DataTable. Таблица, в свою очередь, состоит из столбцов и строк. Каждый столбец представляет объект DataColumn, а строка – объект DataRow. Все данные строки хранятся в свойстве ItemArray, который представляет массив объектов – значений отдельных ячеек строки. Например, получим все таблицы и выведем их содержимое:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
static void Main(string[] args) { string sql = "SELECT * FROM Users"; string connectionString = @"Data Source=.\SQLEXPRESS;Initial Catalog=usersdb;Integrated Security=True"; using (SqlConnection connection = new SqlConnection(connectionString)) { connection.Open(); SqlDataAdapter adapter = new SqlDataAdapter(sql, connection); DataSet ds = new DataSet(); adapter.Fill(ds); // перебор всех таблиц foreach (DataTable dt in ds.Tables) { Console.WriteLine(dt.TableName); // название таблицы // перебор всех столбцов foreach(DataColumn column in dt.Columns) Console.Write("\t{0}", column.ColumnName); Console.WriteLine(); // перебор всех строк таблицы foreach (DataRow row in dt.Rows) { // получаем все ячейки строки var cells = row.ItemArray; foreach (object cell in cells) Console.Write("\t{0}", cell); Console.WriteLine(); } } } } |
Теперь рассмотрим, как мы можем работать с объектами DataSet и DataTable без какой-либо базы данных. Например, создадим вручную в DataSet несколько таблиц и определим их структуру:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
static void Main(string[] args) { DataSet bookStore = new DataSet("BookStore"); DataTable booksTable = new DataTable("Books"); // добавляем таблицу в dataset bookStore.Tables.Add(booksTable); // создаем столбцы для таблицы Books DataColumn idColumn = new DataColumn("Id", Type.GetType("System.Int32")); idColumn.Unique = true; // столбец будет иметь уникальное значение idColumn.AllowDBNull = false; // не может принимать null idColumn.AutoIncrement = true; // будет автоинкрементироваться idColumn.AutoIncrementSeed = 1; // начальное значение idColumn.AutoIncrementStep = 1; // приращении при добавлении новой строки DataColumn nameColumn = new DataColumn("Name", Type.GetType("System.String")); DataColumn priceColumn = new DataColumn("Price", Type.GetType("System.Decimal")); priceColumn.DefaultValue = 100; // значение по умолчанию DataColumn discountColumn = new DataColumn("Discount", Type.GetType("System.Decimal")); discountColumn.Expression = "Price * 0.2"; booksTable.Columns.Add(idColumn); booksTable.Columns.Add(nameColumn); booksTable.Columns.Add(priceColumn); booksTable.Columns.Add(discountColumn); // определяем первичный ключ таблицы books booksTable.PrimaryKey = new DataColumn[] { booksTable.Columns["Id"] }; DataRow row = booksTable.NewRow(); row.ItemArray = new object[] { null, "Война и мир", 200 }; booksTable.Rows.Add(row); // добавляем первую строку booksTable.Rows.Add(new object[] { null, "Отцы и дети", 170 }); // добавляем вторую строку Console.Write("\tИд \tНазвание \tЦена \tСкидка"); Console.WriteLine(); foreach (DataRow r in booksTable.Rows) { foreach (var cell in r.ItemArray) Console.Write("\t{0}", cell); Console.WriteLine(); } Console.Read(); } |
Разберем весь код. Сначала создаются объекты DataSet и DataTable, в конструктор которых передается название. Затем создается четыре столбца. Каждый столбец в конструкторе принимает два параметра: имя столбца и его тип.
1 |
DataColumn idColumn = new DataColumn("Id", Type.GetType("System.Int32")); |
Причем для столбца Id устанавливается, что значения этого столбца должны иметь уникальное значение, не должны принимать null, и их значение при добавлении нового объекта будет инкрементироваться на единицу. То есть фактически это стандартный столбец Id, как в большинстве баз данных.
Далее создается еще три столбца, при этом для столбца Discount устанавливается свойство Expression
, указывающее на выражение, которое будет использоваться для вычисления значения столбца:
1 |
discountColumn.Expression = "Price * 0.2"; |
То есть в данном случае значение столбца Discount равно значению столбца Price, помноженного на 0.2.
Затем устанавливается первичный ключ для таблицы с помощью свойства PrimaryKey:
1 |
booksTable.PrimaryKey = new DataColumn[] { booksTable.Columns["Id"] }; |
В роли первичного ключа выступает столбец Id. Но мы также можем использовать набор различных столбцов для создания составного ключа.
После определения схемы таблицы в нее добавляются две строки:
1 2 3 4 |
DataRow row = booksTable.NewRow(); row.ItemArray = new object[] { null, "Война и мир", 200 }; booksTable.Rows.Add(row); // добавляем первую строку booksTable.Rows.Add(new object[] {null, "Отцы и дети", 170 }); |
Значения в метод booksTable.Rows.Add можно передать как напрямую в виде массива объектов, так и в виде объекта DataRow. При этом нам надо передать ровно столько значений, сколько в таблице столбцов. Однако поскольку первый столбец Id устанавливается через автоинкремент, мы можем передать значение null – оно все равно будет игнорироваться. Также мы можем опустить последний параметр для столбца Discount, так как его значение вычисляется с помощью выражения “Price * 0.2”. Более того мы даже можем опустить значение для третьего столбца Price, так как у него установлено свойство DefaultValue
, которое устанавливает значение по умолчанию, если значение отсутствует:
1 |
booksTable.Rows.Add(new object[] {null, "Отцы и дети"}); |
И в конце идет перебор строк таблицы.
Кроме добавления мы можем производить и другие операции со строками. Например, мы можем получить строку по индексу:
1 |
DataRow row = booksTable.Rows[0]; // первая строка |
Получив строку по индексу, можно изменить ее ячейки:
1 |
booksTable.Rows[0][2] = 300; //третьей ячейке первой строки присваивается значение 300 |
И также можно удалять строку:
1 2 3 4 |
booksTable.Rows.RemoveAt(1); // удаление второй строки по индексу // другой сопосб удаления DataRow row = booksTable.Rows[0]; booksTable.Rows.Remove(row); |
Используя метод Select()
объекта DataTable мы легко можем найти строки, которые соответствуют определенному критерию. Например, получим строки, в которых цена больше 120:
1 2 3 |
var selectedBooks = booksTable.Select("Price > 120"); foreach (var b in selectedBooks) Console.WriteLine("{0} - {1}", b["Name"], b["Price"]); |