DataSet может содержать множество таблиц, которые могут быть связаны различными отношениями. Например, пусть у нас в 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 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
static void Main(string[] args) { DataSet ds = new DataSet("Store"); // таблица компаний DataTable companiesTable = new DataTable("Companies"); // два столбца таблицы Companies DataColumn compIdColumn = new DataColumn("Id", Type.GetType("System.Int32")); compIdColumn.Unique = true; compIdColumn.AllowDBNull = false; compIdColumn.AutoIncrement = true; compIdColumn.AutoIncrementSeed = 1; compIdColumn.AutoIncrementStep = 1; DataColumn compNameColumn = new DataColumn("Name", Type.GetType("System.String")); // добавляем столбцы companiesTable.Columns.Add(compIdColumn); companiesTable.Columns.Add(compNameColumn); // добавляем таблицу в dataset ds.Tables.Add(companiesTable); // вторая таблица - смартфонов компаний DataTable phonesTable = new DataTable("Phones"); DataColumn phoneIdColumn = new DataColumn("Id", Type.GetType("System.Int32")); phoneIdColumn.Unique = true; phoneIdColumn.AllowDBNull = false; phoneIdColumn.AutoIncrement = true; phoneIdColumn.AutoIncrementSeed = 1; phoneIdColumn.AutoIncrementStep = 1; DataColumn phoneNameColumn = new DataColumn("Name", Type.GetType("System.String")); DataColumn phonePriceColumn = new DataColumn("Price", Type.GetType("System.Decimal")); // столбец-внешний ключ DataColumn phoneCompanyColumn = new DataColumn("CompanyId", Type.GetType("System.Int32")); // добавляем столбцы в таблицу смартфонов phonesTable.Columns.Add(phoneIdColumn); phonesTable.Columns.Add(phoneNameColumn); phonesTable.Columns.Add(phonePriceColumn); phonesTable.Columns.Add(phoneCompanyColumn); // добавляем таблицу смартфонов ds.Tables.Add(phonesTable); // установка отношений между таблицами ds.Relations.Add("PhonesCompanies", companiesTable.Columns["Id"], phonesTable.Columns["CompanyId"]); // Добавим ряд данных DataRow apple = companiesTable.NewRow(); apple.ItemArray = new object[] { null, "Apple" }; companiesTable.Rows.Add(apple); DataRow samsung = companiesTable.NewRow(); samsung.ItemArray = new object[] { null, "Samsung" }; companiesTable.Rows.Add(samsung); DataRow iphone5 = phonesTable.NewRow(); iphone5.ItemArray = new object[] { null, "iPhone 5", 400, apple["Id"] }; phonesTable.Rows.Add(iphone5); DataRow iphone6s = phonesTable.NewRow(); iphone6s.ItemArray = new object[] { null, "iPhone 6S", 600, apple["Id"] }; phonesTable.Rows.Add(iphone6s); DataRow galaxy6 = phonesTable.NewRow(); galaxy6.ItemArray = new object[] { null, "Samsung Galaxy S6", 500, samsung["Id"] }; phonesTable.Rows.Add(galaxy6); DataRow galaxyace2 = phonesTable.NewRow(); galaxyace2.ItemArray = new object[] { null, "Samsung Galaxy Ace 2", 200, samsung["Id"] }; phonesTable.Rows.Add(galaxyace2); // выведем все смартфоны компании Apple DataRow[] rows = apple.GetChildRows(ds.Relations["PhonesCompanies"]); Console.WriteLine("Продукция компании Apple"); Console.WriteLine("Id \tСмартфон \tЦена"); foreach (DataRow r in rows) { Console.WriteLine("{0} \t{1} \t{2}", r["Id"], r["Name"], r["Price"]); } Console.Read(); } |
Ключевым моментом здесь является установка отношения между таблицами:
1 |
ds.Relations.Add("PhonesCompanies", companiesTable.Columns["Id"], phonesTable.Columns["CompanyId"]); |
Первым параметром здесь идет название отношения, по которому потом на него можно будет ссылаться. Вторым параметром идет главный столбец – id компании в таблице компаний. Третий параметр – подчиненный столбец – id компании в таблице смартфонов. Подчиненный столбец зависит от главного. Вместо этих параметров мы можем передать объект DataRelation, который также будет иметь данные значения.
Затем используя отношение, мы можем получить для одной строки из таблицы компаний связанные строки из таблицы смартфонов:
1 |
DataRow[] rows = apple.GetChildRows(ds.Relations["PhonesCompanies"]); |
Внешние ключи
Кроме простого отношения между таблицами мы также можем задать внешние ключи, как в обычных базах данных. Для этого непосредственно перед строкой:
1 |
ds.Relations.Add("PhonesCompanies", companiesTable.Columns["Id"], phonesTable.Columns["CompanyId"]); |
Добавим следующий код:
1 2 3 4 5 6 7 8 9 10 11 12 |
ForeignKeyConstraint foreignKey = new ForeignKeyConstraint(companiesTable.Columns["Id"], phonesTable.Columns["CompanyId"]) { ConstraintName = "PhonesCompaniesForeignKey", DeleteRule = Rule.SetNull, UpdateRule = Rule.Cascade }; // добавляем внешний ключ в dataset ds.Tables["Phones"].Constraints.Add(foreignKey); // применяем внешний ключ ds.EnforceConstraints = true; ds.Relations.Add("PhonesCompanies", companiesTable.Columns["Id"], phonesTable.Columns["CompanyId"]); |
Внешний ключ представляет объект ForeignKeyConstraint, в конструктор которого передается два параметра: главный столбец и зависимый столбец. В данном случае это те же самые столбцы.
Также у него мы можем установить ряд свойств. Через свойство ConstraintName
устанавливается название внешнего ключа. Свойства DeleteRule
и UpdateRule
определют поведение при удалении или обновлении данных соответственно в главной таблице (то есть в данном случае в таблице компаний). Эти свойства принимают одно из значений перечисления Rule:
Cascade
: происходит автоматическое изменение или удаление строк в подчиненной таблицеNone
: строки в подчиненной таблице не изменяютсяSetDefault
: происходит установка значений по умолчанию для связанных строк (которое определяется через DataColumn.DefaultValue)SetNull
: для связанных строк устанавливается значение DBNull
С помощью метода ds.Tables["Phones"].Constraints.Add(foreignKey);
внешний ключ добавляется к таблице смартфонов. И затем через выражение ds.EnforceConstraints = true;
происходит применение внешнего ключа.
И если мы удалим, например, одну из строк из таблицы компаний, то в таблице смартфонов все строки, которые связаны с удаленной, в столбце CompanyId будут иметь значение null.