reklama

Poznáváme C# a Microsoft. NET 63. díl – ADO . NET - Datové relace a omezení

V tomto díle, po zmínění jedné zajimavé funkčnosti objektu DataTable, přejdeme k tomu, jak je možné ve světě ADO .NET definovat relace mezi jednotlivými tabulkami v instancích třídy DataSet a také jaké jsou aplikovatelné typy omezení.

Výběr řádku na základě podmínek

Podobně jako lze při použití SQL příkazu SELECT vybrat z databázové tabulky určité záznamy splňujicí námi specifikované podmínky, je možné učinit výběr záznamů z instance třídy DataTable. DataTable za tímto účelem obsahuje definici instanční metody Select, jíž předáme řetězec představující podmínku. Řetězec specifikující tuto podmínku výběru záznamů se řídí stejnými pravidly jako řetězec v případě vlastnosti Expression třídy DataColumn. Použití této metody je tedy jedním ze způsobů, kterým lze uživateli zobrazit filtrovaný seznam záznamů z uživatelem manipulované reprezentace tabulky.
Jako příklad na použití této metody vám může posloužit následující zdrojový kód :

/// <summary>
/// Ukazka pouziti metody Select pro ziskani radku z tabulky podle
/// specifickych podminek
/// </summary>
public class SelectExample
{
 public static void Run()
 {
  DataTable table = MakeTable();
  AddProducts(table);
  //ziskani vsech zaznamu u kterych je cena vetsi nez 3000
  DataRow[] result = table.Select("Price > 3000");
  PrintResult(result);
 }

 //vypise pole objektu DataRow
 static void PrintResult(DataRow[] result)
 {
  ...
 }

 //vytvori objekt DataTable
 static DataTable MakeTable()
 {
  DataTable table = new DataTable("Products");
  table.Columns.Add("Name", typeof(string));
  table.Columns.Add("Price", typeof(int));
  DataColumn idCol = table.Columns.Add("ID", typeof(int));
  idCol.Unique = true;
  idCol.AutoIncrement = true;
  return table;
 }

 //prida zaznamy do objektu DataTable
 static void AddProducts(DataTable table)
 {
  for(int i = 1; i < 10; i++)
  {
   DataRow record = table.NewRow();
   record["Name"] = String.Format("Product No.{0}", i.ToString());
   record["Price"] = i * 1000;
   table.Rows.Add(record);
  }
 }
}

Datové relace

Jak už dobře víme, tak datové tabulky představované objekty DataTable jsou často obsaženy v objektu DataSet. Ve velmi častých případech je při reprezentaci datového zdroje pomocí objektu DataSet v jeho kolekci DataTableCollection obsaženo více než jedna tabulka. Jelikož spolu tyto tabulky povětšinou nějakým způsobem souvisí je možné tuto souvislost vyjádřit pomocí datových relací. Datové relace jsou v ADO .NET reprezentovány instancemi třídy DataRelation a umožňují vyjádřit závislost mezi dvěma tabulkami z nichž jedna je primární a druhá je související (master/detail).

Typickým přikladem na využití relací jsou tabulky kde jedna tabulka obsahuje seznam produtků a druhá obsahuje seznam kategorií do kterých jednotlivé produkty spadají. V takovém případě je primární tabulkou tabulka kategorií a související je tabulka produktů, protože se každý produkt skrze ID kategorie odkazuje na kategorii do které patří. S využitím objektů DataRelation k vyjádření těchto relací jsme po té schopni získat všechny související záznamy k vybranému záznamu z primární tabulky (všechny produkty spadající do konkrétní kategorie). To ovšem není vše, protože je možné využít datovou relaci i ke zjištění informace v opačném směru, tedy zjistit primární záznam ze souvisejícího záznamu (kategorie k danému produktu).

Jak tedy na to? Nejprve se podívejme na zdrojový kód přikladu a po té si jej rozebereme.

/// <summary>
/// Priklad na pouziti objektu DataRelation
/// </summary>
public class DataRelationsExample
{
 public static void Run()
  {
  //vytvoreni DataSetu
  DataSet data = new DataSet();
  //vytvoreni tabulek
  DataTable products = MakeProductTable();
  DataTable categories = MakeCategoryTable();
  //naplneni tabulek
  AddCategories(categories);
  AddProducts(products);
  //prirazeni tabulek k DataSetu
  data.Tables.Add(products);
  data.Tables.Add(categories);
  //vytvoreni relace mezi tabulkami
  DataRelation rel = new DataRelation("ProductCategory", categories.Columns["ID"], products.Columns["Category"]);
  //prirazeni relace k datasetu
  data.Relations.Add(rel);
  //ziskani produktu pro prvni kategorii
  DataRow[] children = categories.Rows[0].GetChildRows("ProductCategory");
  //vypsani ziskanych produktu
  PrintResult(children);
  //ke kazdemu evidovanemu produktu vypiseme jeho kategorii
  foreach(DataRow product in products.Rows)
  {
   DataRow category = product.GetParentRow("ProductCategory");
   Console.WriteLine("Produkt {0} patri do kategorie {1}", product["Name"], category["Name"]);
  }
 }

 //vypise pole objektu DataRow
 static void PrintResult(DataRow[] result)
 {
  ...
 }
  
 //vytvori schema tabulky produktu
 internal static DataTable MakeProductTable()
 {
  DataTable table = new DataTable("Products");
  DataColumn idCol = table.Columns.Add("ID", typeof(int));
  table.Columns.Add("Name", typeof(string));
  table.Columns.Add("Price", typeof(int));
  table.Columns.Add("Category", typeof(int));
  idCol.Unique = true;
  idCol.AutoIncrement = true;
  idCol.AutoIncrementSeed = 1;
  idCol.AllowDBNull = false;
  return table;
 }

 //vytvori schema tabulky kategorii
 internal static DataTable MakeCategoryTable()
 {
  DataTable table = new DataTable("Categories");
  DataColumn idCol = table.Columns.Add("ID", typeof(int));
  table.Columns.Add("Name", typeof(string));
  idCol.Unique = true;
  idCol.AllowDBNull = false;
  idCol.AutoIncrement = true;
  idCol.AutoIncrementSeed = 1;
  return table;
 }
 //vytvori do tabulky produktu par zaznamu
 internal static void AddProducts(DataTable table)
 {
  ...
 }

 //vytvori do tabulky kategorii par zaznamu
 internal static void AddCategories(DataTable table)
 {
  ...
 }
}

V příkladu jsou tedy vytvořeny dvě tabulky, kde jedna obsahuje záznamy o produktech a druhá o kategoriích. To do jaké kategorie produkt patří je specifikováno ve sloupci Category ve kterém je uloženo její ID. Po naplění těchto tabulek trochou zkušebních dat je vytvořen objekt DataRelation představující datovou relaci mezi těmito dvěma tabulkami. V příkladu je použit konstruktor třídy DataRelation u kterého je potřeba specifikovat název této relace a pak také sloupce, přes které jsou jednotlivé tabulky propojeny, kde prvním je sloupec primární tabulky (Categories) a druhým sloupec ze související tabulky (Products). K tomu, abychom mohli vyžívat výhod spojených s vytvořením této relace musíme objekt relace přidat do kolekce DataRelationCollection objektu DataSet, do kterého naše tabulky patří.

Po té jsme již schopni získat související záznamy pro vybraný primární záznam, tedy v našem příkladu vybereme všechny produkty spadající do určité kategorie. Toho dosáhneme použitím metody GetChildRows na záznamu o kategorii, která nám vrátí pole objektů DataRow z tabulky o produktech, které představují záznamy o souvisejících produktech. Jak jsem již psal, tak je možné získat na souvisejícím záznamu jeho primární záznam a to učiníme použitím metody GetParentRow.

Omezující podmínky

V prostředí ADO .NET je možné definovat omezující podmínky vztahující se k jednotlivým sloupcům v objektu DataTable. Jejich funkce je obdobná omezením ve světě databázových tabulek. Bázovou třídou pro třídy, jejichž instance představují nějaké omezení, je třída Constraint ze jmenného prostoru System.Data. Konkrétní implementace jsou představovány třídami UniqueConstraint a ForeignKeyConstraint. První z nich slouží k omezení, které vynucuje jedinečnost záznamů v rámci jednoho objektu DataTable a druhá vynucuje propojení mezi dvěma objekty DataTable v rámci jednoho objektu DataSet.

Objekty typu UniqueConstraint jsou vytvářeny automaticky při nastavení vlastnosti Unique typu DataColumn na true, nebo při nastavení primárního klíče objektu DataTable, pomocí vlastností PrimaryKey. Explicitním vytvořením tohoto objektu však můžeme definovat název tohoto omezení, který je jinak automaticky generován.

DataSet data = new DataSet();
DataTable table = new DataTable();
data.Tables.Add(table);
//nastaveni objektu DataSet, aby vynucoval omezeni
data.EnforceConstraints = true;
DataColumn idCol = table.Columns.Add("ID", typeof(int));
//vytvoreni objektu omezeni
UniqueConstraint constraint = new UniqueConstraint("ID_con", idCol);
table.Constraints.Add(constraint);
DataRow row = table.NewRow();
row["ID"] = 1;
table.Rows.Add(row);
DataRow row2 = table.NewRow();
row2["ID"] = 1;
//bude vyhozena vyjimka
table.Rows.Add(row2);

Omezení typu ForeignKeyConstraint se hodí v případech primární/související, kterým jsme se již v podobě kategorie/produkt v tomto díle setkali. Použitím těchto objektů omezení je možné definovat operace, které se se souvisejícími záznamy provedou v případě, že je primární záznam změněn nebo odstraněn, což je opět analogie k omezenim ve světě databází.

Následující příklad ukazuje použití objektu ForeignKeyConstraint a nastavuje operace, které se mají dít v případě změn či smazání primárních záznamů.

/// <summary>
/// Priklad na pouziti objektu ForeignKeyConstraint
/// </summary>
public class ForeignKeysExample
{
 public static void Run()
 {
  //vytvoreni objektu DataSet
  DataSet data = new DataSet();
  //vytvoreni tabulek
  DataTable products = MakeProductTable();
  DataTable categories = MakeCategoryTable();
  //naplneni tabulek
  data.Tables.Add(products);
  data.Tables.Add(categories);

  AddProducts(products);
  AddCategories(categories);
  //vytvoreni omezeni mezi tabulkami
  ForeignKeyConstraint constraint = new ForeignKeyConstraint("FK_Product_Category", categories.Columns["ID"], products.Columns["Category"]);
  //pridani do kolekce omezeni tabulky produtku
  products.Constraints.Add(constraint);
  //nastaveni akci pri uprave/smazani asociovane galerie
  constraint.UpdateRule = Rule.Cascade;
  constraint.DeleteRule = Rule.SetNull;
   
  //nastaveni objektu DataSet, aby vynucoval omezeni
  data.EnforceConstraints = true;
  Console.WriteLine("Pred zmenou tabulky categories :");
  PrintTable(products);
  //ziskani a upraveni zaznamu o prvni kategorii
  DataRow selectedCategory = categories.Select("ID = 1")[0];
  selectedCategory["ID"] = 10;
  Console.WriteLine("Po zmene tabulky categories :");
  PrintTable(products);
 }
}

Vytvoření tohoto objektu omezeni je v našem příkladu stejné jako vytvoření objektu DataRelation, tedy předáním názvu omezení a primárního respektive souvisejícího sloupce. Velmi důležité je nastavení vlastností UpdateRule a DeleteRule, které určují jako operace mají být provedeny se souvisejícími záznamy v případě změny respektive smazání jejich primárního záznamu. Hodnota Cascade výčtu Rule, která je v našem případě použita u změny primárního záznamu specifikuje, že při každé změně hodnoty primárního klíče v primární tabulce dojde i k automatické aktualizaci hodnot v souvisejících záznamech. To je také v našem příkladu ukázáno a to tak ,že když je změněno ID první kategorie z hodnoty 1 na hodnotu 10, tak jsou aktualizovány i hodnoty sloupce Category v záznamech tabulky produktů. Hodnota SetNull výčtu Rule je použita u vlastnosti DeleteRule našeho objektu omezení a znamená, že pokud je primární záznam smazán, jsou hodnoty v souvisejících záznamech nastavenu na hodnotu DBNull. Takže v případě, že bychom v našem příkladu smazali například první kategorii, tak by záznamy o produktech, které do ní patřili,  měli ve sloupci Category hodnotu DBNull.

Jistě jste si všimli, že je v obou příkladech na definici omezeni pracováno s vlastností EnforceConstraints objektu DataSet. Tato vlastnost určuje jestli budou u obsažených tabulek objektu DataSet definovaná omezení vynucována.


Příklady ke článku naleznete zde.

Témata článku: Software, Microsoft, Programování, Public

3 komentáře

Nejnovější komentáře

  • Pavel Polívka 24. 11. 2007 13:53:36
    Programovou oflline verzi seriálu naleznete ke stažení na...
  • datel12, datel12 14. 4. 2006 15:06:14
    Dokumentace je součástí VS.NET případně je online na webu MSDN...
  • iwata 1. 3. 2006 17:59:30
    Ahoj, asi to sem nepatri, ale chtel bych se zeptat, kde se da stahnout...
reklama
Určitě si přečtěte

UPC překopli páteřní kabel. V Brně i druhý den nejede internet ani kabelovka

UPC překopli páteřní kabel. V Brně i druhý den nejede internet ani kabelovka

** V Brně byl velký výpadek služeb UPC ** Důvodem je překopnutý páteřní kabel ** V některých lokalitách služby stále nefungují

5.  12.  2016 | Jakub Čížek | 100

17 expertek Microsoftu předpovědělo rok 2027. Splní se alespoň něco?

17 expertek Microsoftu předpovědělo rok 2027. Splní se alespoň něco?

** Zmizí klasické vyhledávače ** Budeme programovat buňky ** Kvantové počítače překonají šifry

6.  12.  2016 | Jakub Čížek | 36

11 tipů na dobrý stolní počítač: od základu po herní mašiny

11 tipů na dobrý stolní počítač: od základu po herní mašiny

** Postavte si stolní počítač! Máme pro vás 11 vzorových sestav s rozpisem komponent ** Většina tipů cílí na hráče, věnujeme se ale i základnímu PC a počítačům na střih videa ** Nadělte si nový počítač třeba pod stromeček

5.  12.  2016 | Adam Kahánek | 73


reklama