reklama

Poznáváme C# a Microsoft .NET 65. – ADO .NET – stavitel dotazů a ukládání DataSetu do XML

Dnešní díl si klade za úkol čtenáře seznámit se zajímavým způsobem tvorby příkazů pro datový adaptér a také jak je možné využít formát XML pro uložení či načtení objektu DataSet.

Stavitel dotazů

V minulém díle, kdy jsme se zaobírali datovými adaptéry, jsme zjistili, že pro obousměrnou synchronizaci datové sady, tedy objektu DataSet se souvisejícím datovým zdrojem je potřebné použit datový adaptér, který má správně definovány všechny čtyři příkazy (SelectCommand, InsertCommand, UpdateCommand a DeleteCommand). To ovšem, jak jistě víte, znamená určité úsilí, protože pro příkazy upravující související datový zdroj jsou parametrické a je potřeba uvést mapování pro každý sloupec. Pokud se budeme chtít definici těchto příkazů efektivně vyhnout, využijeme takzvaného stavitele dotazů.

Stavitel dotazů je pro každý specifický ADO .NET data provider představován jinou třídou jak je již v ADO .NET zvykem, avšak na rozdíl od ostatních součástí ADO .NET neexistuje společné rozhraní (typu IDataAdapter, IDbCommand..), které je pro konkrétní datového poskytovatele implementováno. Takže v základní knihovně tříd nalezneme stavitelé dotazů pro základní datové poskytovatele, kterými jsou SqlCommandBuilder, OracleCommandBuilder, OleDbCommandBuilder a OdbcCommandBuilder.

Pokud stavitele dotazů asociujeme s datovým adaptérem, tak je stavitel schopen vygenerovat příkazy InsertCommand, UpdateCommand a DeleteCommand asociovaného datového adaptéru. Jediné úsilí, které musíme při vytváření adaptéru vyvinout je definice vlastnosti SelectCommand. Proč je tomu tak? Stavitel totiž použije výsledkovou sadu získanou pomocí příkazu SelectCommand a na základě schématu této sady vygeneruje ostatní dotazy. Pomocí stavitele dotazů jsme tedy schopni velmi zrychlit vývoj naší aplikace, která pracuje z daty v odpojeném režimu. Následující zdrojový kód představuje příklad na použití třídy SqlCommandBuilder, což je stavitel dotazů pro MS SQL Server.

public sealed class CommandBuilderExample
{
  public static void Run()
  {
    SqlConnection connection = new SqlConnection(@"...");
    SqlDataAdapter adapter = GetAdapter(connection);
    DataSet dataset = new DataSet();
    //naplnime dataset daty
    adapter.Fill(dataset, "employees");
   
    DataRow record = dataset.Tables["Employees"].Rows[0];
    record["FirstName"] = "Upravene jmeno";

    //tento kod by bez pouziti stavitele dotazu skoncil chybou
    adapter.Update(dataset, "employees");
}

  private static SqlDataAdapter GetAdapter(SqlConnection connection)
  {
    SqlDataAdapter result = new SqlDataAdapter();
    result.SelectCommand = new SqlCommand("select * from employee",connection);
    //asociace stavitele s datovym adapterem
    SqlCommandBuilder builder = new SqlCommandBuilder(result);
    return result;
  }
}

Jak vidíte, tak využití stavitele dotazů je velmi jednoduché, stačí pouze asociovat stavitele s daným datovým adaptérem, což provedeme buď konstruktorem, jak je tomu v našem příkladu a nebo nastavením instanční vlastnosti DataAdapter. A pokud má daný datový adaptér nastavenou vlastnost SelectCommand, můžeme již směle volat metodu Update našeho adaptéru a vše ostatní můžeme ponechat na staviteli. Příkazy jsou stavitelem sestrojeny v případě prvního volání metody Update našeho adaptéru. Stavitel se totiž po asociaci s datovým adaptérem stane odběratelem (pozorovatelem) události RowUpdating datového adaptéru, která je vyvolávána při průběhu metody Update a tak je stavitel schopen včas zareagovat vygenerováním příslušných příkazů. Používá k tomu své metody GetInsertCommand, GetUpdateCommand a GetDeleteCommand a jelikož jsou tyto metody veřejné, nic nám nebrání je ze svého kódu v případě potřeby využít. Po spuštění následujícího kódu získáte výpis vygenerovaných parametrických dotazů.

SqlConnection connection = new SqlConnection(@"...");
//jedine co je potreba nastavit je vlastnost SelectCommand
SqlDataAdapter adapter = new SqlDataAdapter("select * from employee", connection);
SqlCommandBuilder builder = new SqlCommandBuilder(adapter);
     
Console.WriteLine("Insert command : {0}", builder.GetInsertCommand().CommandText);
Console.WriteLine("Update command : {0}", builder.GetUpdateCommand().CommandText);
Console.WriteLine("Delete command : {0}", builder.GetDeleteCommand().CommandText);

I když nám při práci v odpojeném prostředí může stavitel dotazů ušetřit spoustu práce je třeba splnit také určité podmínky. Definovaný příkaz představující SelectCommand daného datového adaptéru, musí vracet výsledkovou sadu v níž alespoň jeden sloupec představuje primární klíč nebo sloupec s unikátními hodnotami (v našem případě sloupec ID), jinak by pokus o sestavení příkazu UpdateCommand nebo DeleteCommand skončilo vyhozením výjimky.

Kromě této věci je dobré vědět, že před prvním vygenerováním jakéhokoli příkazu pomocí stavitele je proveden příkaz SelectCommand datového adaptéru nad datovým zdrojem za účelem získání schématu tabulky, což samozřejmě znamená určitou ztrátu výkonu, kterou je v určitých případech dobré brát v potaz.

DataSet a XML

Jedním ze zásadních cílů návrhu komponenty ADO .NET bylo její silné spojení s formátem XML. Třída DataSet, jakožto stěžejní prvek ADO .NET, disponuje vlastností zapsat se do formátu XML a naopak také se z XML načíst. Díky této vlastnosti je mimochodem například možné používat instance třídy DataSet u aplikací založených na XML webových službách. DataSet za účelem uložení se obsahuje metodu WriteXml a za účelem načtení se metodu ReadXml. XML představující DataSet může být obecně zapsán do jakéhokoli datového proudu. Informace zapsané do XML jsou bohaté. Nejen, že jsou zapsány jednotlivé objekty DataTable, ale případně i relace mezi nimi a také je možné do XML datového proudu zapsat informace popisující schéma daného objektu DataSet. Následující příklad ukazuje, jak je možné zapsat obsah objektu DataSet do XML a následně tento obsah načíst.

/// <summary>
/// Priklad na export/import DataSetu do/z XML
/// </summary>
public class DataSetXML
{
  public static void Run()
  {
    //jmeno datasetu se projevi v XML
    DataSet ds = new DataSet("DataSetZive");
    //vytvoreni tabulky
    DataTable employeesTable = CreateEmployeeTable();
    //naplneni tabulky
    CreateEmployees(employeesTable);
    ds.Tables.Add(employeesTable);
    //zapsani do XML
    ds.WriteXml("employees.xml");
    //vymazani obsahu datasetu
    ds.Clear();
    Console.WriteLine("Pocet zaznamu v tabulce employees : {0}", ds.Tables["employees"].Rows.Count);
    //nacteni obsahu z XML souboru
    ds.ReadXml("employees.xml");
    Console.WriteLine("Pocet zaznamu v tabulce employees po precteni XML: {0}", ds.Tables["employees"].Rows.Count);
  }

  static DataTable CreateEmployeeTable()
  {
    DataTable table = new DataTable("employees");
    DataColumn idCol = table.Columns.Add("ID", typeof(int));
    table.Columns.Add("FirstName", typeof(string));
    table.Columns.Add("SurName", typeof(string));
    idCol.Unique = true;
    idCol.AutoIncrement = true;
    idCol.AllowDBNull = false;
    return table;
  }

  static void CreateEmployees(DataTable table)
  {
    DataRow pusRow = table.NewRow();
    pusRow["FirstName"] = "Petr";
    pusRow["SurName"] = "Pus";

    DataRow racekRow = table.NewRow();
    racekRow["FirstName"] = "Michal";
    racekRow["SurName"] = "Racek";

    table.Rows.Add(pusRow);
    table.Rows.Add(racekRow);
  }
}

To, že jsem využil přetížené verze konstruktoru třídy DataSet, která přijímá jméno nově vznikající instance, se projeví ve výsledném XML jak za chvíli uvidíme. Metoda WriteXml také existuje v několika přetížených verzích. Já jsem v příkladu použil jednoduchou verzi přijímající jméno souboru do kterého bude výsledný XML datový proud zapsán, ovšem je možné využít i jinou přetíženou verzi této metody a zapsat DataSet do jakéhokoli jiného typu datového proudu. Stejně je tomu i v případě metody ReadXml. Soubor XML by měl po spuštění tohoto příkladu obsahovat následující obsah.

<?xml version="1.0" standalone="yes"?>
<DataSetZive>
  <employees>
    <ID>0</ID>
    <FirstName>Petr</FirstName>
    <SurName>Pus</SurName>
  </employees>
  <employees>
    <ID>1</ID>
    <FirstName>Michal</FirstName>
    <SurName>Racek</SurName>
  </employees>
</DataSetZive>

Hlavním elementem je námi specifikovaný název objektu DataSet a po té následuje vždy element se jménem objektu DataTable v němž jsou jednotlivé složky záznamu (DataRow) z tohoto objektu.

Jak jsem zmínil o pár řádek výše tak kromě obsažených dat a případných relací mezi tabulkami je možné do XML zapsat i údaje o schématu objektu DataSet. Toho docílíme použitím přetížené verze metody WriteXml, které přijímá kromě cíle zápisu, také hodnotu z výčtu XmlWriteMode. Také je možné analogickým způsobem zařídit načtení schématu objektu DataSet z XML.

//zapsani do XML
ds.WriteXml("employees.xml", XmlWriteMode.WriteSchema);
...
//nacteni obsahu z XML souboru
ds.ReadXml("employees.xml",XmlReadMode.ReadSchema);

Příklady ke článku jsou k dispozici zde.

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

1 komentář

Nejnovější komentáře

  • Pavel Polívka 24. 11. 2007 13:55:11
    Programovou oflline verzi seriálu naleznete ke stažení na...
reklama
Určitě si přečtěte

Microsoft: Zbavte se už konečně zastaralých a děravých Windows 7

Microsoft: Zbavte se už konečně zastaralých a děravých Windows 7

** Microsoft pomalu začíná kritizovat svůj nejpopulárnější OS ** Chce konečně dostat podniky na Desítky ** Bezpečnostní podpora Sedmiček vydrží ještě necelé tři roky

17.  1.  2017 | Jakub Čížek | 402

Český státní blacklist už funguje. Ministerstvo financí se pochlubilo s detaily

Český státní blacklist už funguje. Ministerstvo financí se pochlubilo s detaily

** Dva týdny po Novém roce zajím zeje prázdnotou ** Ministerstvo vydalo metodický pokyn ** Takhle to bude fungovat v praxi

16.  1.  2017 | Jakub Čížek | 49

Opera Neon: Takto prý bude vypadat prohlížeč budoucnosti. Chcete to?

Opera Neon: Takto prý bude vypadat prohlížeč budoucnosti. Chcete to?

** Opera představila Neon ** Koncepci prohlížeče budoucnosti ** Připomíná Chrome OS

16.  1.  2017 | Jakub Čížek | 35

Testy ze světa: Kaby Lake v high-endu splnil povinnost, Pentia jsou ale překvapením

Testy ze světa: Kaby Lake v high-endu splnil povinnost, Pentia jsou ale překvapením

** Na světě jsou testy porovnávající nové procesory řady Kaby Lake ** Modely Core i5 a Core i7 toho nenabízí mnoho navíc oproti Skylake ** Pozornost na sebe upoutala levná Pentia, která dostala podporu HT

17.  1.  2017 | Stanislav Janů | 55


Aktuální číslo časopisu Computer

99 nejlepších programů pro váš počítač

Zvykejte si na umělou inteligenci

Velké testy PC zdrojů a gamepadů

Alternativní zdroje energie

reklama
reklama