Poznáváme C# a Microsoft .NET 56. díl – ADO .NET - Implementace připojených aplikací

V tomto díle navážeme na díl předchozí a podíváme se trochu blíže na možnosti použití typu IDataReader a také jak je možné využít typ IDbCommand v připojeném scénáři přístupu k datovému zdroji.

Další možnosti typu IDataReader

V minulém díle již byla ukázána implementace přístupu k datům pomocí typu IDataReader, kde se k hodnotám pro jednotlivé sloupce v řádku přistupovalo pomocí indexeru, který představoval vlastnost Item definovanou na rozhraní IDataRecord (jež rozhraní IDataReader rozšiřuje).

Kromě této vlastnosti definuje rozhraní IDataRecord i poměrně početnou sadu metod, které vracejí tyto hodnoty již jako konkrétní typy CTS (Common Type System), takže například metoda GetInt32 vrací hodnotu daného sloupce aktuálního řádku přetypovanou na typ Int32, tedy typ int jazyka C#, samozřejmě pokud je takovéto přetypování možné. Těchto metod využijeme v případě, kdy přesně víme, jakých typů jsou jednotlivé sloupce v databázové tabulce.

/// <summary>
/// Priklad na pouziti Get* metod implementace rozhrani IDataReader
/// </summary>
public class DataReaderExample1
{
  public static void PrintAllEmployees()
  {
    IDbConnection lConnection = new SqlConnection(@"data source=`dellak\sql1`;initial catalog=`zive`;integrated security=`sspi`");
    IDbCommand lCommand = new SqlCommand("select * from employee");
    lCommand.Connection = lConnection;
    IDataReader lReader = null;
    try
    {
      lConnection.Open();
      lReader = lCommand.ExecuteReader();
      //pri cteni budou hodnoty sloupcu ziskany pomoci specifickych metod
      while (lReader.Read())
      {
        //id
        int lId = lReader.GetInt32(0);
        //jmeno
        string lFirstName = lReader.GetString(1);
        //prijmeni
        string lSurName = lReader.GetString(2);
        //datum narozeni
        DateTime lBirthDate = lReader.GetDateTime(3);
        Console.WriteLine("{0} - {1} - {2} - {3}", lId, lFirstName, lSurName, lBirthDate);
      }
    }
    catch(SqlException ex)
    {
    Console.WriteLine("Nastala vyjimka : {0}", ex.ToString());
    }
    finally
    {
      if (lReader != null && !lReader.IsClosed)
      {
        lReader.Close();
      }
      if (lConnection != null && !lConnection.State.Equals(ConnectionState.Closed))
      {
        lConnection.Close();
      }
    }
  }
}

Kromě těchto metod vracejících hodnoty o specifických typech je na rozhraní IDataReader definována i metoda GetValue, která vrací hodnotu typu System.Object a po té je možné ji explicitně přetypovat, což je v podstatě stejná funkčnost jako pří použití již známého indexeru (vlastnost Item). Pokud chceme získat hodnoty všech sloupců pro aktuální řádek je možné využít metody GetValues a pomocí ní dostaneme pole objektů typu System.Object obsahující kýžené hodnoty.

V příkladu je při zavírání objektu IDataReader, kromě kontroly toho jestli byl objekt inicializován (test na null) také využito vlastnosti IsClosed, podle které zjistíme jestli je již reader uzavřen (podle názvu nečekaně). Také při zavíraní připojení k databázi je mimo kontroly na hodnotu null přečtena vlastnost State, jež je typu ConnectionState, což je výčet představující možné stavy daného přípojení. Při kontrole se ověří jestli již není spojení uzavřeno.

Uzavření spojení spolu s uzavřením data readeru

V častých implementačních scénářích budeme spojení k databázi uzavírat ihned po zavření objektu typu IDataReader, kdy už jsou data přečtena tak jak je prováděno v uvedených příkladech.

Existuje možnost jak zařídit, aby byla konexe k databázi uzavřena ve chvíli, kdy je uzavřen IDataReader. Metoda ExecuteReader typu IDbCommand, existuje totiž v přetížené verzi přijímající parametr typu CommandBehavior. Pomocí tohoto výčtu můžeme definovat příznaky (je na něj použit atribut Flags), které ovlivní chování IDataReaderu. Příznak, který nám zajistí požadovanou operaci, tedy uzavření spojení spolu s IDataReaderem je hodnota CloseConnection.

/// <summary>
/// Ukazka pouziti uzitecne pretizene verze metody ExecuteReader implementace
/// rozhrani IDbCommand
/// </summary>
public class DataReaderExample2
{
  public static void PrintAllEmployees()
  {
    IDbConnection lConnection = new SqlConnection(@"data source=`dellak\sql1`;initial catalog=`zive`;integrated security=`sspi`");
    IDbCommand lCommand = lConnection.CreateCommand();
    lCommand.CommandText = "select * from employee";
    IDataReader lReader = null;
    try
    {
      lConnection.Open();
      //chceme, aby bylo pripojeni zavreno spolu se zavrenim readeru
      lReader = lCommand.ExecuteReader(CommandBehavior.CloseConnection);
      while (lReader.Read())
      {
        //operace cteni dat z vysledkove sady
      }
    }
    finally
    {
      if (lReader != null && !lReader.IsClosed)
      {
        //zavreni pripojeni k databazi je provedeno
        //po zavreni readeru
        lReader.Close();
      }
    }
    Console.WriteLine("Stav pripojeni : {0}", lConnection.State);
  }
}

Další využití typu IDbCommand

Prozatím jsme implementovali pouze situace, kdy jsme data četli. Jak ale v připojené aplikaci, kromě již známého čtení pomocí IDataReaderu, data v databázi upravovat? Velmi jednoduše pomocí instancí tříd implementujících rozhraní IDbCommand. K vyvolání příkazu stačí jen použít metody ExecuteNonQuery. Tato metoda je primárně určena pro vykonávání sql příkazů INSERT, UPDATE nebo DELETE.

/// <summary>
/// Ukazka pouziti implementace rozhrani IDbCommand pro vlozeni
/// radku do databaze v pripojene aplikaci
/// </summary>
public class InsertingDataExample
{
  public static void Run()
  {
    InsertRow("Petr", "Fisar", DateTime.Now.AddYears(-20));
  }

  public static void InsertRow(string firstName, string surName, DateTime birthDate)
  {
    IDbConnection lConnection = new SqlConnection(@"data source=`dellak\sql1`; initial catalog=`zive`; integrated security=`sspi`");
    IDbCommand lCommand = lConnection.CreateCommand();
    //vytvoreni sql prikazu pro vlozeni radku
    lCommand.CommandText = String.Format("insert into employee (FirstName, SurName, BirthDate) values (`{0}`,`{1}`,`{2}`)", firstName, surName, birthDate);
    Console.WriteLine(lCommand.CommandText);
    try
    {
      lConnection.Open();
      //spusteni prikazu
      lCommand.ExecuteNonQuery();
      Console.WriteLine("Zaznam byl pridan");
    }
    catch(SqlException ex)
    {
      Console.WriteLine("Nastala vyjimka : {0}", ex);
    }
    finally
    {
      if (lConnection != null && !lConnection.State.Equals(ConnectionState.Closed))
      {
        lConnection.Close();
      }
    }
  }
}

Na rozdíl do metody ExecuteReader vracející odkaz na IDataReader užívaný ke čtení výsledkové sady, tak metoda ExecuteNonQuery vrací pouze číslo indikující kolik záznamů v datovém zdroji bylo příkazem ovlivněno. To se může hodit hlavně v případě UPDATE či DELETE příkazů.

/// <summary>
/// Priklad na ukazku zjisteni poctu zasazenych radku dotazem
/// vyvolanym pres metodu ExecuteNonQuery typu IDbCommand
/// </summary>
public class DeletingDataExample
{
  public static void DeleteRow(int id)
  {
    IDbConnection lConnection = new SqlConnection(@"data source=`dellak\sql1`; initial catalog=`zive`; integrated security=`sspi`");
    IDbCommand lCommand = lConnection.CreateCommand();
    lCommand.CommandText = String.Format("delete from employee where ID={0}", id);
    try
    {
      lConnection.Open();
      //metoda vraci pocet zasazenych radku
      int lAffected = lCommand.ExecuteNonQuery();
      Console.WriteLine("Pocet zasazenych radku : {0}", lAffected);
    }
    catch(SqlException ex)
    {
      Console.WriteLine("Nastala vyjimka : {0}", ex);
    }
    finally
    {
      if (lConnection != null && !lConnection.State.Equals(ConnectionState.Closed))
      {
        lConnection.Close();
      }
    }
  }
}

Nezajímavou také není metoda ExecuteScalar tohoto typu. Tato metoda nalezne jistě uplatnění v případě použití různých SQL agregačních funkcí. Návratovou hodnotou této metody je totiž první sloupec prvního řádku ze získané výsledkové sady. Takže pokud bychom chtěli zjistit počet evidovaných zaměstnanců v naší databázi, mohli bychom pro vyřešení tohoto požadavku použít následující implementací.

/// <summary>
/// Priklad na vyuziti metody ExecuteScalar typu IDbCommand
/// </summary>
public class SelectCountExam
{
  public static void PrintCount()
  {
    IDbConnection lConnection = new SqlConnection(@"data source=`dellak\sql1`; initial catalog=`zive`; integrated security=`sspi`");
    IDbCommand lCommand = lConnection.CreateCommand();
    //sql dotaz vrati pocet vsech radku v tabulce
    lCommand.CommandText = "select count(*) from employee";
    try
    {
      lConnection.Open();
      object lResult =  lCommand.ExecuteScalar();
      Console.WriteLine("Pocet evidovanych zamestnancu : {0}", lResult);
    }
    catch(SqlException ex)
    {
    Console.WriteLine("Nastala vyjimka : {0}", ex);
    }
    finally
    {
      if (lConnection != null && !lConnection.State.Equals(ConnectionState.Closed))
      {
        lConnection.Close();
      }
    }
  }
}

Příklady ke článku si můžete stáhnout zde.

Příště se ještě budeme zabývat problematikou implementace připojených aplikací a podíváme se například na parametrizované příkazy.

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

2 komentáře

Nejnovější komentáře

  • Pavel Polívka 24. 11. 2007 13:49:29
    Programovou oflline verzi seriálu naleznete ke stažení na...
  • fantasy 16. 1. 2006 11:12:30
    Nevim, jestli se na to dostanete, presto bych Vas Petre poprosil v...
Určitě si přečtěte

Sbíječky vyměnili za klávesnice. Nový projekt má za cíl přeučit horníky na programátory

Sbíječky vyměnili za klávesnice. Nový projekt má za cíl přeučit horníky na programátory

** Programátorů je málo a horníků bez práce po uzavření dolu Paskov bude moc ** Problém řeší unikátní projekt ** Pilotní kurz dává naději, že by z horníků mohli být použitelní kodéři

28.  11.  2016 | David Polesný | 79

ASUS ZenBook 3 se začal prodávat v Česku. Je ve všem lepší než MacBook, ale bude to stačit?

ASUS ZenBook 3 se začal prodávat v Česku. Je ve všem lepší než MacBook, ale bude to stačit?

** Novinka od Asusu míří přímo proti MacBooku od Applu ** Nabídne daleko více výkonu za stejné peníze

2.  12.  2016 | David Polesný | 127