Bejelentkezés

E-mail: 
Jelszó: 
| Regisztráció | Jelszó? |
 



Menü

.Net világ havilap 2004. július - 5. oldal

ADO.NET alapok

A  System.Data  névtérben  található  osztályokkal  foglalkozunk  e  cikkben,  melyek  az  ADO.NET  alapjait  képezik.A  cikk  elsősorban  azoknak  szól,  akik  még  csak  most  ismerkednek  a  .NET  Framework  adatelérési  lehetőségeivel.  Nagy  vonalakban  áttekintjük  a  cikk  során  az  ADO.NET  alapjait,  legfontosabb  lehetőségeit,  mintegy  bevezetőképpen  megismertetjük  az  alapokat  a  további  cikkek  megértéséhez. 

ADO.NETAz  adatok  kezelése  nem  feltétlen  az  adatbázisos  rendszereknél  kezdődik.  E  cikkben  se  MS  SQL,  se  Oracle,  se  egyéb  adatforráshoz  nem  fordulunk,  mégis  megismerjük  minden  apró  részletét  annak  a  módszernek,  mellyel  az  adatbázisban  lévő  adatok  is  kezelhetők.  A  System.Data  névtér  osztályai  képesek  jól  szervezetten  tárolni  és  kezelni  az  adatokat,  melyek  származhatnak  bárhonnan,  akár  programból  generált  adatokból,  akár  adatbázisokból,  vagy  bármilyen  egyéb  típusú  adatállományokból.  Az  ADO.NET  használatával  teljesen  egységes  módon  kezelhető  bármilyen  típusú  adatforrásból  származó  adat,  melynek  felépítése  a  következő:  vannak  adathalmazok,  melyekben  adattáblákat  találunk,  minden  adattábla  egy  kétdimenziós  adattárolónak  tekinthető,  melyen  vannak  adatsorok  és  adatoszlopok.  Az  adathalmazt  a  DataSet  osztály  képviseli,  mely  egy  kollekcióban  tárolja  az  adattáblákat,  amelyek  DataTable  osztályban  kapnak  helyen.  Minden  DataTable  egy  újabb  kollekcióban  tárolja  az  adatsorokat  a  DataRow  osztályt  felhasználva.  Végezetül  az  adatsorok  egy  újabb  kollekcióban  helyezik  el  az  adott  sorban  található  adatokat  Object  típusként.Ezen  osztályok  persze  csak  a  legalapvetőbbek,  legfontosabbak  az  adatok  kezelésében,  melyek  a  System.Data  névtérben  találhatók.  A  mellékelt  példaprogramban  több  lapra  osztva  végigtekintünk  a  teljesség  igénye  nélkül  néhány  fontos  és  alapvető  műveletet  az  ADO.NET  világában,  melyek  a  leggyakrabban  előfordulnak  egy  valós  alkalmazás  készítésekor.1  lap:  adatlétrehozás,  megjelenítésElsődleges  feladatunk  egy  adathalmaz  létrehozása  és  annak  láthatóvá  tétele  a  programunkban.  Az  adattároláshoz  egy  DataSet  osztályt  deklarálunk,  mely  globálisan  elérhető  lesz  a  Form1-en  belül  bárhonnan,  így  az  itt  létrehozott  adatokat  a  későbbiekben  is  felhasználhatjuk  bemutatónk  különféle  feladatainak  megvalósításakor.private  DataSet  ds1;Az  adatok  létrehozását  a  Form1  konstruktorában  végezzük  el.  Itt  létrehozunk  egy  DataSet  példányt,  melynek  névként  az  "Adathalmaz"  sztringet  adjuk.  Ez  a  névadás  nem  kötelező  jellegű,  elvégezhetnénk  ezt  a  műveletet  paraméter  megadása  nélkül  is.  Példaprogram  első  lapja                public  Form1()        {            InitializeComponent();            ds1  =  new  DataSet("Adathalmaz");A  DataSet  osztály  feladata,  hogy  több  adattáblát  tároljon,  szükség  esetén  a  közöttük  fennálló  relációval  együtt.  Nézzük  miként  is  megy  egy  DataTable  osztály  létrehozása:  a  DataTable  konstruktorában  szintén  megadhatunk  egy  tetszőleges  elnevezést  sztringként,  mely  az  adattábla  neve  lesz.  Ez  éppúgy  nem  kötelező,  mint  a  DataSet  esetén,  de  így  lehetőségünk  lesz  majd  a  későbbiek  folyamán  név  alapján  hivatkozni  az  adattáblára  és  nem  csak  sorszám  alapján.  A  név  alapú  hivatkozás  előnye,  hogy  forráskódunk  áttekinthetőbbé  és  ily  módon  könnyebben  fejleszthetővé  válik.  Hiszen  egy  szöveges  megnevezés  alapján  hamarabb  eszünkbe  jut,  hogy  mit  is  tartalmaz,  mi  is  a  célja  az  adott  táblának,  mintha  csak  egy  sorszámot  látnánk.            DataTable  dt1  =  new  DataTable("Adattábla  1");A  DataTable  létrehozását  követően  annak  oszlopait  kell  létrehoznunk,  megadva  az  oszlopneveket  és  oszloptípusokat.  E  műveletet  a  DataTable  Columns  nevű  property-n  keresztül  tehetjük  meg.  E  kollekció  tárolja  az  adattábla  oszlopainak  adatait.  Új  oszlopot  az  Add  függvénnyel  vehetünk  fel,  melynek  több  változata  is  létezik.  A  legegyszerűbb  eset,  amikor  a  függvény  első  paraméterébe  az  oszlop  nevét  adjuk  meg  sztringként,  míg  a  másodikba  annak  típusát  Type  osztályként.              dt1.Columns.Add("ID",                  Type.GetType("System.Int32"));            dt1.Columns.Add("Name",                  Type.GetType("System.String"));Amikor  majdan  egy  adatbázisból  lekérdezünk  adatokat,  akkor  nem  kell  nekünk  megadni  az  oszlopok  típusát  és  méretét,  mivel  ez  a  lekérdezett  adatok  alapján  automatikusan  létrejön  majd.Miután  létrejöttek  az  oszlopok,  máris  lehetőségünk  van  új  adatsorok  felvételére  a  táblába.  Amikor  a  DataTable  osztály  NewRow  függvényét  hívjuk,  akkor  az  visszaad  egy  olyan  DataRow  osztályt,  mely  egyetlen  adatsort  képvisel  és  amelyben  annyi  oszlop  van,  ahányat  a  DataTable  osztályba  felvettünk.  Az  oszlopokat  azok  nevei  alapján  érhetjük  el,  de  lehetőségünk  van  elhelyezkedésük  sorszáma  alapján  is  azonosítani  őket.  Az  így  megcímzett  adattároló  egységeknek  egyszerűen  értéket  adhatunk  olyan  típusú  adatokkal,  melyek  egyeznek  az  adatoszlop  típusával.            DataRow  dr1  =  dt1.NewRow();            dr1["ID"]  =  1;            dr1["Name"]  =  "Nyúl  Béla";A  DataTable  NewRow  függvényének  hívásával  még  jön  létre  új  sor  a  DataTable-be!  Nem  árt,  ha  ezt  jól  megjegyezzük,  hogy  a  NewRow  csupán  létrehoz  egy  új  DataRow  példányt  a  tábla  szerkezetének  megfelelően,  de  ha  azt  akarjuk,  hogy  ez  az  új  sor,  a  megadott  adatainkkal  ténylegesen  a  DataTable-ben  tárolásra  is  kerüljön,  akkor  a  DataTable  osztály  Rows  property-jét  kell  használnunk,  mely  nem  más,  mint  az  adatsorokat  tároló  kollekció.  Ennek  Add  függvényét  meghívva  hozzáadhatunk  egy  új  sort  a  DataTable-hez.            dt1.Rows.Add(dr1);Adjunk  a  DataTable-hez  most  egy  második  sort  is,  a  fenti  módszert  követve.            dr1  =  dt1.NewRow();            dr1["ID"]  =  2;            dr1["Name"]  =  "Gipsz  Jakab";            dt1.Rows.Add(dr1);Mivel  a  DataSet  képes  több  DataTable  tárolására,  így  létrehozunk  egy  második  táblát  is  a  későbbi  különféle  tesztek  elvégzéséhez.            DataTable  dt2  =  new  DataTable("Adattábla  2");            dt2.Columns.Add("ID",                  Type.GetType("System.Int32"));            dt2.Columns.Add("OrderDate",                  Type.GetType("System.DateTime"));Megfigyelhető,  hogy  mindkét  táblánál  létrehoztunk  egy  ID  nevű  Int32  típusú  oszlopot.  Ezen  adat  segítségével  képesek  leszünk  majd  reláció  létrehozására  a  két  tábla  adatai  között.Hozzunk  most  létre  a  második  táblához  is  adatsorokat,  melyeket  most  egy  ciklus  segítségével  teszünk  meg.            DataRow  dr2;            for  (int  i=0;  i<10;  i++)            {A  NewRow  függvény  hívásával  létrehozunk  egy  új  sort,  melybe  felveszünk  adatokat,  amit  eltárolunk  a  második  adattáblába,  a  már  ismert  módon.                dr2  =  dt2.NewRow();                dr2["ID"]  =  i  %  2  +  1;                dr2["OrderDate"]  =  DateTime.Now.AddMonths(i);                dt2.Rows.Add(dr2);            }Miután  mindkét  adattáblát  létrehoztuk  és  feltöltöttük,  eltároljuk  azokat  a  DataSet-be.  A  DataSet  az  adattáblákat  a  Tables  property-jében  tárolja  egy  kollekcióban.  Ebbe  új  táblát  az  Add  függvény  segítségével  vehetünk  fel.            ds1.Tables.Add(dt1);            ds1.Tables.Add(dt2);        }Ha  programunkban  csupán  csak  egyetlen  DataTable-re  lenne  szükségünk  a  munkánkhoz,  akkor  nem  is  lenne  szükséges  a  DataSet  osztályt  alkalmaznunk,  hacsak  nem  szeretnénk  elérni  annak  speciális  funkcióit.A  szükséges  adatok  most  tehát  már  rendelkezésünkre  állnak.A  button1  gomb  lenyomásakor  az  ablak  első  lapján  lévő  DataGrid-ben  megjelenítjük  az  első  adattáblát.  Tesszük  ezt  úgy,  hogy  a  DataGrid  kontrol  DataSource  property-jének  értékül  adjuk  a  megjeleníteni  kívánt  adatot,  mely  jelen  esetben  a  DataSet  osztály  Tables  kollekciójában  lévő  "Adattábla  1"  névre  hallgató  DataTable  osztály  lesz.  A  DataGrid-ben  jól  látható  módon  megfigyelhető  az  első  adattábla  programból  létrehozott  szerkezete  és  adatai.        private  void  button1_Click(object  sender,                System.EventArgs  e)        {            dataGrid1.DataSource  =                    ds1.Tables["Adattábla  1"];        }A  button2  gomb  lenyomásakor  az  előzőekhez  hasonlóan  megjelenítjük  a  másodikként  létrehozott  adattáblánkat.        private  void  button2_Click(object  sender,              System.EventArgs  e)        {            dataGrid1.DataSource  =                  ds1.Tables["Adattábla  2"];        }Mi  történik  akkor,  ha  a  DataGrid  DataSource  property-jének  magát  a  DataSet  osztály  példányát  adjuk  meg?  Ekkor  a  DataGrid-ben  megjelenik  két  link,  mely  a  két  táblára  mutat.  A  linkek  feliratai  a  táblák  létrehozásánál  megadott  neveket  tartalmazzák.  Ha  valamely  linkre  kattintunk,  akkor  a  DataGrid  automatikusan  betölti  a  kiválasztott  táblát  épp  úgy,  mint  ahogyan  a  button1  és  button2  gomb  lenyomásakor  mi  magunk  tettük.        private  void  button3_Click(object  sender,              System.EventArgs  e)        {            dataGrid1.DataSource  =  ds1;        }Programból  arra  is  lehetőségünk  van,  hogy  végigmenjünk  egy  DataSet  összes  tábláján  és  azokkal  tetszőleges  műveleteket  végezzünk.  A  button5  gombra  történő  kattintás  esetén  egy  foreach  ciklussal  haladunk  végig  a  DataSet  minden  DataTable-jén,  mely  egy  DataTableCollection  típusú  kollekcióban  kapott  helyet  és  egy  ListBox-ba  megjelenítjük  az  egyes  táblák  elnevezéseit.  A  neveket  a  TableName  property  szolgáltatja.  Ez  a  szöveg  a  tábla  megnevezése  lesz,  melyet  a  létrehozásuknál  adtunk  meg.        private  void  button5_Click(object  sender,              System.EventArgs  e)        {            foreach  (DataTable  dt  in  ds1.Tables)            {                listBox1.Items.Add(dt.TableName);            }        }2  lap:  adatok  elérése  és  megváltoztatása  Példaprogram  második  lapjaMost,  hogy  már  rendelkezésünkre  állnak  adatok,  megnézzük,  hogy  miként  is  tudjuk  azokat  programból  elérni  és  igény  szerint  megváltoztatni.  Feladatunk  az  lesz,  hogy  érjük  el  a  másodikként  létrehozott  adattábla  első  sorában  és  második  oszlopában  lévő  dátum  adatot  és  azt  véletlenszerűen  változtassuk  meg.1  gombAz  adott  cellában  lévő  dátumhoz  hozzáadunk  egy  -10000  és  +10000  közötti  értéket  napokban  mérve.        private  void  button4_Click(object  sender,                System.EventArgs  e)        {            int  i  =  new  Random().Next(20000)  -  10000;Az  adat  eléréséhez  a  DataSet  osztály  Tables  property-jéből  az  1-es  sorszámú  DataTable-t  vesszük  ki.  Mivel  a  számozás  nullától  indul,  így  ez  a  másodikként  létrehozott  táblát  jelenti.            DataTable  dt  =  ds1.Tables[1];Az  adattábla  első  sorát  a  DataTable  osztály  Rows  property-jén  keresztül  érhetjük  el.  A  számozás  itt  is  nullától  indul,  így  ezt  az  elemet  tároljuk  egy  DataRow  osztályba.            DataRow  dr  =  dt.Rows[0];A  változtatni  kívánt  adat  a  második  oszlopban  található  és  így  a  szokás  szerint  nullától  induló  sorszámozás  miatt  a  DataRow  1-es  elemét  kell  megcímeznünk  és  értékül  adnunk  egy  új  DateTime  típusban  tárolt  dátumot.            dr[1]  =  DateTime.Now.AddDays(i);Az  érték  ezzel  meg  is  változott,  azt  akár  rögtön  ki  is  olvashatjuk.            label1.Text  =  dr[1].ToString();Ahhoz,  hogy  a  DataTable-ben  bekövetkezett  változás  a  DataGrid-ben  is  láthatóvá  váljék,  ismét  a  DataGrid  DataSource  property-jéhez  kell  kötnünk  a  második  adattáblát.            dataGrid2.DataSource  =                  ds1.Tables["Adattábla  2"];        }2.  gombA  második  gomb  lenyomásánál  ugyanazt  a  műveletet  végezzük  el,  mint  az  előző  esetben,  de  most  egy  kicsit  más  módon.        private  void  button6_Click(object  sender,              System.EventArgs  e)        {            int  i  =  new  Random().Next(20000)  -  10000;Mostani  megoldásunkban  csupán  egyetlen  forráskódnyi  sor  elegendő  a  kívánt  hatás  eléréséhez,  mivel  nem  hozunk  létre  változókat,  melyekben  tároljuk  a  részeredményeket,  hanem  felhasználjuk  azt,  hogy  az  egyik  objektum  által  visszaadott  osztály  rögtön  tovább  címezhető  egy  másik  tulajdonságán  keresztül:            ds1.Tables[1].Rows[0][1]  =                    DateTime.Now.AddDays(i);Fentiekben  a  ds1  nevű  DataSet  osztály  Tables  kollekciójának  második  elemében  lévő  sorok  közül  a  Rows  property  segítségével  érjük  el  az  első  sort,  ebben  pedig  a  második  adatoszlopnak  adunk  értékül  egy  új  dátumot.            label1.Text  =                    ds1.Tables[1].Rows[0][1].ToString();            dataGrid2.DataSource  =                    ds1.Tables["Adattábla  2"];                }Ez  a  tömörebb  írási  mód  minden  olyan  esetben,  amikor  egyszer  kell  elérni  az  adott  objektumot,  sokkal  célravezetőbb.  Ellenben,  ha  egy-egy  objektumot  többször  is  el  kell  érnünk,  akkor  ez  a  kód  már  nem  hatékony,  mivel  minden  egyes  esetben  újra  és  újra  megcímezzük  az  adott  objektum  adott  alobjektumát,  ami  felesleges  processzor  időtöltéssel  jár,  vagyis  lassítja  az  alkalmazásunkat.Így  nézne  ki  egy  olyan  kód,  mely  nem  hatékony:        ds1.Tables[1].Rows[0][1]  =  ...;        ds1.Tables[1].Rows[1][1]  =  ...;        ds1.Tables[1].Rows[2][1]  =  ...;        ds1.Tables[1].Rows[3][1]  =  ...;        ds1.Tables[1].Rows[4][1]  =  ...;        ds1.Tables[1].Rows[5][1]  =  ...;        ...Fentieket  így  lenne  célszerű  megvalósítani:        DataRowCollection  drc  =  ds1.Tables[1].Rows;        drc[0][1]  =  ...;        drc[1][1]  =  ...;        drc[2][1]  =  ...;        drc[3][1]  =  ...;        drc[4][1]  =  ...;        drc[5][1]  =  ...;        ...    3.  gombA  harmadik  gomb  lenyomásakor  még  mindig  ugyanazt  a  műveletet  végezzük  el,  mint  a  fentiekben,  de  most  ismét  egy  kissé  más  módon  tesszük  azt.        private  void  button7_Click(object  sender,              System.EventArgs  e)        {            int  i  =  new  Random().Next(20000)  -  10000;Jelen  esetben  felhasználjuk  azt,  hogy  az  egyes  objektumoknak  számunkra  is  könnyen  értelmezhető  nevüket  használjuk  azok  azonosítására.  Így  elkerülhető  az,  hogy  esetleg  rosszul  emlékezünk  arra,  hogy  egy  adattáblát  hányadikként  is  tároltunk  el  a  DataSet-be  és  így  esetleg  egy  rossz  adattáblát  címzünk  meg.  További  probléma  lehet,  a  szám  alapján  történő  azonosítás  esetén  az  is,  hogy  ha  továbbfejlesztjük  alkalmazásunkat  és  például  az  első  és  második  tábla  közé  beszúrunk  egy  harmadikat,  akkor  a  ds1.Tables[1]  hivatkozás  már  az  új  táblára  vonatkozik  és  nem  arra,  mely  eredetileg  a  második  volt.  Ez  ismét  csak  számos  nem  várt  következménnyel  járhat,  nem  beszélve  arról,  hogy  ilyen  esetben  igen  sok  helyen  kellene  átjavítanunk  forráskódunkban  a  sorszámokat  ds1.Tables[2]-re.Célszerű  tehát  mindig  név  alapján  azonosítani  ezeket  az  objektumokat,  így  nem  érhet  bennünket  meglepetés,  hiszen  mindig  azt  az  adatot  érjük  el,  melyre  szükségünk  van  és  még  forráskódunk  is  olvashatóbbá  válik.A  név  alapján  történő  azonosítás  esetén  nincs  semmi  különbség  az  előző  forráskódhoz  képest,  leszámítva  azt,  hogy  ahol  eddig  sorszámokat  használtunk,  ott  ahol  csak  lehet,  most  szöveges  azonosítókat  adunk  meg:            ds1.Tables["Adattábla  2"].Rows[0]["OrderDate"]                    =  DateTime.Now.AddDays(i);            label1.Text  =                  ds1.Tables["Adattábla2"].Rows[0]                ["OrderDate"].ToString();            dataGrid2.DataSource  =                  ds1.Tables["Adattábla  2"];                }3  lap:  adatsor  állapota  Példaprogram  harmadik  lapjaAmikor  egy  DataTable  osztály  adatsoraiban  tárolt  értékeken  változtatunk,  akkor  a  DataTable  "megjegyzi",  hogy  melyik  sort  érintette  e  módosítás.  Úgyis  mondhatnánk,  hogy  minden  egyes  sornak  van  egy  állapotjelzője,  melyet  felhasználva  megtudhatjuk,  hogy  melyik  sor  milyen  állapotban  van  éppen.  Ez  az  információ  sok  esetben  hasznos.  Például  a  felhasználó  több  sor,  több  adatát  is  módosítja,  melyeket  adatbázisban  is  tárolnunk  kell.  Ekkor  nyilvánvaló,  hogy  csak  azokat  a  sorokat  érdemes  frissíteni  az  adatbázisban,  melyek  ténylegesen  módosultak.Amikor  létrehozunk  egy  új  sort,  akkor  annak  állapota  tükrözi,  hogy  egy  új  tételről  van  szó  az  adataink  között.  Ehhez  hasonlóan  egy  törölt  sor  sem  tűnik  el  véglegesen,  hanem  csak  törlésre  megjelölt  állapotú  lesz.Amikor  bármilyen  módon  változtatunk  az  adatainkon,  akkor  az  AcceptChanges  függvény  segítségével  véglegesíthetjük  a  pillanatnyi  állapotot.  Ekkor  minden  adatsor  alapállapotú  lesz.A  változtatásokat  el  is  vethetjük  és  ezáltal  visszaállíthatjuk  az  eredeti  állapotot  a  RejectChanges  függvény  hívásával.  Ez  a  függvény  a  legutolsó  AcceptChanges  hívása  óta  bekövetkezett  változtatásokat  vonja  vissza.Az  AcceptChanges  és  RejectChanges  függvények  léteznek  a  DataSet,  DataTable  és  a  DataRow  osztályokban  is.  Hatásuk  minden  esetben  egyező,  különbség  csupán  a  hatókörükben  található.  A  DataRow  osztályban  lévő  függvények  hívásakor  csak  az  adott  sorra  nézve  hajtódnak  végre  a  műveletek.  A  DataTable  osztálybeli  függvények  meghívása  a  táblában  tárolt  összes  sorra  vonatkozik,  míg  a  DataSet  osztályban  lévő  függvények  meghívásakor  a  DataSet  minden  táblájának  minden  sorára  érvényesek  lesznek  az  előírt  műveletek.State  gombA  már  létrehozott  két  adattáblánk  esetében  nem  foglalkoztunk  sem  az  állapot  kezeléssel,  sem  annak  módosításával.  A  State  gombra  kattintva  most  megnézhetjük,  hogy  a  sorok  milyen  állapotban  vannak  aktuálisan.  A  Form-on  a  baloldali  DataGrid-ben  a  másodikként  létrehozott  adattábla  látható,  míg  a  jobb  oldaliban  az  egyes  sorok  állapota.  Hogy  az  állapotokat  is  egy  DataGrid-ben  jeleníthessük  meg,  gyorsan  létrehozunk  egy  DataTable-t,  melynek  egyetlen  State  nevű  oszlopa  lesz.        private  void  button8_Click(object  sender,              System.EventArgs  e)        {            DataTable  dtState  =  new  DataTable();            dtState.Columns.Add("State");            DataRow  drState;Ezt  követően  egy  ciklussal  végigmegyünk  a  második  adattáblánkon  és  minden  egyes  sorának  állapotát  eltároljuk  az  imént  létrehozott  adattáblába.  A  sorok  állapotát  a  DataRow  osztály  RowState  property-je  tárolja,  mely  egy  felsorolt  típusú  adat  lesz.            DataTable  dt1  =  ds1.Tables["Adattábla  2"];            foreach  (DataRow  dr  in  dt1.Rows)            {                drState  =  dtState.NewRow();                drState["State"]  =  dr.RowState.ToString();                dtState.Rows.Add(drState);            }                    dataGrid4.DataSource  =  dtState;        }Accept  gombHa  meghívjuk  az  adattáblára  az  AcceptChanges  függvényt,  akkor  jól  látható,  hogy  minden  sor  állapota  Unchanged-re  változik,  mivel  az  AcceptChanges  érvényesít  minden  addigi  változást  és  így  a  sorok  állapota  alaphelyzetbe  kerül.        private  void  button9_Click(object  sender,              System.EventArgs  e)        {            DataTable  dt1  =  ds1.Tables["Adattábla  2"];            dt1.AcceptChanges();            button8_Click(null,  null);        }Change  gombVégezzünk  most  változtatást  az  adattáblánk  harmadik  és  hatodik  sorában  lévő  dátumokon  és  figyeljük  meg,  hogy  miként  változik  ezen  sorok  állapota.        private  void  button10_Click(object  sender,              System.EventArgs  e)        {            DataRow  dr;            dr  =  ds1.Tables["Adattábla  2"].Rows[2];            dr["OrderDate"]  =                  ((DateTime)dr["OrderDate"]).AddDays(-10);            dr  =  ds1.Tables["Adattábla  2"].Rows[5];            dr["OrderDate"]  =                  ((DateTime)dr["OrderDate"]).AddDays(-10);            dataGrid3.DataSource  =                    ds1.Tables["Adattábla  2"];                    button8_Click(null,  null);        }Reject  gombA  Change  gombnál  történt  változtatásokat  érvényteleníthetjük  a  Reject  gombra  történő  kattintással,  vagy  akár  érvényesíthetjük  is  azokat,  ha  ismét  az  Accept  gombunkra  kattintunk.A  Reject  gombnál  a  DataTable  osztály  RejectChanges  függvényét  hívjuk,  így  minden  soron  történt  változtatást  visszavonunk.        private  void  button12_Click(object  sender,  System.EventArgs  e)        {            DataTable  dt1  =  ds1.Tables["Adattábla  2"];            dt1.RejectChanges();            button8_Click(null,  null);        }  Add  gombAz  Add  gomb  lenyomásakor  azt  vizsgáljuk  meg,  hogy  milyen  módon  változhat  meg  egy  sor  állapota.  Ennél  a  gombnál  sorra  vesszük  az  összes  lehetséges  állapotot,  mely  az  alábbiak  egyike  lehet:Állapot LeírásDetached Az  új  sor  létre  lett  hozva,  de  még  nem  lett  az  adattáblához  adva.Added Az  új  sor  az  adattáblához  lett  adva,  de  az  AcceptChanges  függvény  még  nem  futott.Unchanged Az  AcceptChanges  függvény  futása  óta  nem  történt  változás  az  adatokban.Modified Az  AcceptChanges  függvény  futása  óta  történt  változás  az  adatokban.Deleted Az  adatsor  a  Delete  függvénnyel  törölve  lett.Első  lépésben  egy  DataTable  változóba  tároljuk  a  második  adattáblánkat.        private  void  button11_Click(object  sender,              System.EventArgs  e)        {            listBox2.Items.Clear();            DataTable  dt;            DataRow  dr;            dt  =  ds1.Tables["Adattábla  2"];  Majd  létrehozunk  egy  új  sort  a  DataTable  osztály  NewRow  függvényével.  Mivel  ez  a  sor  még  nem  lett  hozzáadva  a  DataTable-hez,  így  sor  állapota  Detached  lesz.            dr  =  dt.NewRow();            listBox2.Items.Add(dr.RowState.ToString());Amint  ezt  a  sort  tároljuk  a  DataTable-ben  az  állapota  Added-re  változik.            dt.Rows.Add(dr);            listBox2.Items.Add(dr.RowState.ToString());Az  új  sor  hozzáadását  véglegesítjük  az  AcceptChanges  függvény  hívásával,  így  a  sor  állapota  Unchanged-re  vált  át.            dt.AcceptChanges();            listBox2.Items.Add(dr.RowState.ToString());Ha  módosítjuk  e  sor  valamely  adatát,  akkor  a  sor  állapota  Changed-re  változik.            dr["OrderDate"]  =  DateTime.Now;            listBox2.Items.Add(dr.RowState.ToString());Amint  töröljük  a  létrehozott  sorunkat  az  állapota  Deleted  lesz.            dr.Delete();            listBox2.Items.Add(dr.RowState.ToString());            button8_Click(null,  null);        }4.  lap:  adatsor  verziókezelése  és  szerkesztése  Példaprogram  negyedik  lapjaPéldaprogramunk  negyedik  lapján  azzal  ismerkedünk,  hogy  miként  kezelhetjük  egy-egy  adatsor  különböző  verzióit,  valamint,  hogy  milyen  hatása  van  az  adatszerkesztéssel  kapcsolatos  függvényeknek.Amint  az  az  előző  oldal  példáiból  már  sejthető,  az  adattábla  nem  csak  az  egyes  sorok  állapotát  jegyzi  fel,  hanem  egy  esetleges  adatváltozás  esetén  a  sor  eredeti  verzióját  is  megőrzi.  Ez  nyilván  szükséges  is,  hiszen  különben  a  RejectedChanges  nem  lenne  képes  helyreállítani  az  eredeti  állapotot.  Egy-egy  sor  tehát  több  példányban  is  tárolásra  kerül,  többféle  verziója  létezik.1.  gombAz  1-es  gombra  kattintva  második  adattáblánk  épp  aktuális  módosításait  érvényesítsük  az  AcceptChanges  hívásával.        private  void  button13_Click_1(object  sender,              System.EventArgs  e)        {            DataTable  dt  =  ds1.Tables["Adattábla  2"];            dt.AcceptChanges();Ezt  követően  töröljük  le  a  6.  sort  és  módosítsuk  a  2.  sor  OrderDate  oszlopát.            dt.Rows[5].Delete();            dt.Rows[1]["OrderDate"]  =  DateTime.Now;A  harmadik  sort  nyissuk  meg  szerkesztésre  a  BeginEdit  függvény  hívásával  és  csak  ezek  után  változtassuk  meg  itt  is  az  OrderDate  oszlop  értékét.E  változtatások  értelmét  a  következőkben  hamarosan  meglátjuk.            dt.Rows[2].BeginEdit();            dt.Rows[2]["OrderDate"]  =  DateTime.Now;            dataGrid5.DataSource  =  dt;A  listBox3-ba  felvesszük  egy  adatsor  lehetséges  verzióinak  a  megnevezéseit,  melyeket  a  DataRowVersion  felsorolt  típus  tartalmaz.  Ennek  megnevezéseit  sztring  tömbként  az  Enum  osztály  GetNames  függvénye  szolgáltatja  számunkra.            listBox3.Items.AddRange(Enum.GetNames(                typeof(DataRowVersion)));        }ListBox-ra  történő  kattintásMiután  a  listBox3-ba  feltöltöttük  a  neveket,  így  ezzel  lehetőséget  biztosítunk  az  adatsorok  különféle  verzióinak  a  hozzáféréséhez.  A  kívánt  verziók  megtekintéséhez  csak  e  ListBox-ra  kell  kattintani.  Mivel  az  1-es  gombnál  módosítottunk,  töröltünk,  így  mindenféle  verziójú  sor  a  rendelkezésre  áll  majd  a  teszthez.Amikor  a  ListBox-on  kattintás  történik,  akkor  annak  SelectedIndexChanged  eseményét  felhasználva  értesülhetünk  arról,  hogy  listát  kell  készíteni  egy  kiválasztott  verziójú  adatsorokról.        private  void  listBox3_SelectedIndexChanged(object              sender,  System.EventArgs  e)        {A  választott  verziót  a  ListBox-ból  csak  sztringként  érjük  el,  melyet  most  vissza  kell  alakítanunk  DataRowVersion  típussá.  Ehhez  az  Enum  osztály  Parse  függvényét  használjuk,  melynek  első  paramétereként  a  létrehozandó  típusról  kell  információt  megadnunk,  míg  másodikként  a  felsorolt  típus  választott  elemét  sztringként.            DataRowVersion  drv  =  (DataRowVersion)                Enum.Parse(typeof(DataRowVersion),                  listBox3.SelectedItem.ToString(),  false);Most  lekérhetünk  egy  DataTable-t  a  DataSet-től  a  már  ismert  módon.            DataTable  dt  =  ds1.Tables["Adattábla  2"];            listBox4.Items.Clear();A  sorokon  egy  foreach  ciklussal  haladunk  végig.            foreach  (DataRow  dr  in  dt.Rows)            {A  ciklusmagban  ellenőrizzük  a  DataRow  osztály  HasVersion  property-jén  keresztül,  hogy  az  adott  sornál  a  kiválasztott  verzió  egyáltalán  létezik-e  vagy  sem.                if  (dr.HasVersion(drv))  {Amennyiben  létezik  ez  a  verzió,  úgy  a  listBox4-be  írjuk  a  sor  adatait.  Ahhoz,  hogy  egy  adatsorban  tárolt  adatnak  egy  régebbi  verzióját  érjük  el,  a  DataRow  indexelőjében  nem  csupán  a  kívánt  elem  megnevezését,  vagy  a  sorszámát  kell  megadnunk,  hanem  másodikként  a  verziót  is  DataRowVersion  típusként:                    listBox4.Items.Add(dr["ID",  drv].ToString()                            +  "  -  "  +  dr["OrderDate",                            drv].ToString());                }            }        }E  módszerre  minden  létező  verzió  típust  megnézhetünk  az  adattáblánkban,  de  lássuk  milyen  eredményt  is  szolgáltat  a  mellékelt  példa:Először  is  tekintsük  át,  milyen  verziók  léteznek:Verzió LeírásCurrent A  sor  aktuális  verziója.Default Amennyiben  a  sor  állapota  Added  vagy  Modified  a  Default  verzió  egyezik  a  Current  verzióval.Amennyiben  a  sor  állapota  Deleted,  a  Default  verzió  egyezik  az  Original  verzióval.Amennyiben  a  sor  állapota  Detached,  a  Default  verzió  egyezik  a  Proposed  verzióval.Original A  sor  eredeti  értékei.Proposed A  sor  tervezett  értékei.Amikor  tehát  a  ListBox-ból  az  Original  tételt  választjuk,  akkor  az  1-es  gombnál  végzett  módosítások  előtti  állapotot  láthatjuk  viszont,  vagyis  a  legutóbbi  AcceptChange  függvény  hívása  utáni  állapotot.Amikor  a  ListBox-ból  a  Proposed  tételt  jelöljük  ki,  lesz  látható  a  1-es  gombnál  a  Delete  függvénnyel  törölt  sor.A  Current  és  az  Original  verzió  közötti  különbséget  ha  alaposan  megfigyeljük,  akkor  látható,  hogy  az  1-es  gombnál  módosított  2.  sor  esetén  az  Original  verzió  egy  régebbi  időpontot  mutat,  mint  a  Current  verzió.  Ez  így  is  van  rendjén,  hiszen  itt  megváltoztattuk  ezt  az  értéket  az  aktuális  időpontra:            dt.Rows[1]["OrderDate"]  =  DateTime.Now;Szintén  az  1-es  gombnál  megváltoztattuk  a  3.  sor  dátumát  is  az  aktuális  időpontra:            dt.Rows[2].BeginEdit();            dt.Rows[2]["OrderDate"]  =  DateTime.Now;Itt  viszont  a  változtatás  előtt  meghívtuk  a  sor  BeginEdit  függvényét,  így  a  Current  és  az  Original  verzió  között  nem  látunk  majd  semmilyen  különbséget,  mivel  a  sor  jelenleg  még  szerkesztés  alatt  áll  a  BeginEdit  hívása  miatt.  Ha  viszont  a  Default  verziót  választjuk,  akkor  már  e  3.  sor  is  az  új  értéket  mutatja,  mint  a  sor  tervezett,  de  még  nem  végleges  értékét.2.  gombA  BeginEdit  függvény  hatása  tehát  az,  hogy  megnyithatunk  egy  sort  szerkesztésre  és  így  amíg  ezt  az  állapotot  fenntartjuk,  a  sor  adatait  tetszés  szerint  módosíthatjuk,  de  ezek  a  módosítások  még  nem  jutnak  érvényre  mindaddig,  amíg  az  EndEdit  függvényt  meg  nem  hívjuk.Lehetőségünk  van  arra  is,  hogy  a  szerkesztésre  megnyitott  sor  változtatásait  visszavonjuk.  Ehhez  a  sor  CancelEdit  függvényét  kell  meghívnunk.  A  2-es  gomb  lenyomásakor  a  következőt  tesszük:  egy  DataRow  osztályba  kiolvassuk  a  harmadik  sort,  amelyet  az  1-es  gombnál  a  BeginEdit  függvény  hívásával  megnyitottunk  szerkesztésre.        private  void  button14_Click(object  sender,              System.EventArgs  e){            DataRow  dr  =  ds1.Tables["Adattábla  2"].Rows[2];Ezek  után  ellenőrizzük,  hogy  van-e  a  sornak  tervezett  verziója.            if  (dr.HasVersion(DataRowVersion.Proposed)){Amennyiben  igen,  akkor  ellenőrizzük,  hogy  az  OrderDate  oszlop  aktuális  adata  egyezik-e  a  tervezett  adattal.  Ebből  a  vizsgálatból  megállapítható,  hogy  az  adat  változott-e  azóta,  hogy  a  BeginEdit  futott.              if  (dr["OrderDate",  DataRowVersion.Current]                    ==  dr["OrderDate",  DataRowVersion.Proposed])              {Amennyiben  a  két  verziójú  adat  egyezik,  akkor  biztosak  lehetünk  benne,  hogy  nincs  változás,  így  a  CancelEdit  függvény  hívásával  lezárhatjuk  a  sor  szerkesztését,  mely  egyúttal  érvénytelenítené  is  az  esetleges  változtatásokat.                    dr.CancelEdit();              }Amennyiben  a  két  verziójú  adat  különböző,  úgy  tudhatjuk,  hogy  a  BeginEdit  hívása  óta  ez  az  adat  megváltozott,  így  az  EndEdit  hívásával  érvényesíthetjük  az  új  adatot  és  egyúttal  lezárhatjuk  a  sor  szerkesztésre  megnyitott  állapotát.                else                {                    dr.EndEdit();                }            }            dataGrid5.DataSource  =                  ds1.Tables["Adattábla  2"];        }5  lap:  adatsor  hibajelzési  lehetőségei  Példaprogram  ötödik  lapjaFelhasználói  adatbevitel  során,  vagy  egy  adatelemzési  folyamat  végén  gyakran  előforduló  és  megoldandó  feladat,  hogy  valamilyen  módon  kiemeljünk  néhány  adatot  a  többi  közül.  A  DataRow  osztály  rendelkezik  egy  olyan  lehetőséggel,  hogy  tetszőleges  szöveges  adatot  tároljunk  el  a  sor  bármely  oszlopának  értékéhez,  vagy  akár  az  egész  sorhoz.  Bár  elsősorban  ezt  a  funkciót  hibajelzésre  találták  ki,  de  hogy  ezt  az  adatot  később  mire  használjuk  fel,  az  leginkább  csak  rajtunk  múlik.  Például  a  DataGrid  kontrol  képes  a  DataRow-ban  megadott  ilyen  jellegű  üzenetek  figyelésére,  kezelésére.  Ha  egy  adatnál  talál  szöveges  információt,  akkor  az  adott  cellában  egy  kis  piros  körben  lévő  fehér  felkiáltójelet  helyez  el,  mely  fölé  egérrel  állva  megjeleníti  a  megadott  szövegünket  is.  Amennyiben  a  szöveget  nem  egy  konkrét  adathoz  rendeltük,  hanem  az  egész  sorhoz,  akkor  a  DataGrid  a  kontrol  bal  szélén  lévő  oszlopban  jeleníti  meg  a  kis  piros  ikont.SetColumnError  gombA  mellékelt  példában  a  SetColumnError  gombra  kattintva  néhány  sornál  beállítunk  ilyen  hibaüzenetet,  a  teszt  kedvéért.        private  void  button15_Click(object  sender,              System.EventArgs  e)        {            DataTable  dt  =  ds1.Tables["Adattábla  2"];            dt.AcceptChanges();            DateTime  d;            int  i;A  hibaüzenetek  megadásához  a  második  adattábla  minden  során  végighaladunk.            foreach  (DataRow  dr  in  dt.Rows)            {Ha  találunk  olyan  sort,  melynél  az  ID  oszlop  értéke  nem  egy,  akkor  egy  hibaüzenetet  helyezünk  el.  Ehhez  a  DataRow  osztály  SetColumnError  függvényét  kell  meghívnunk.  Ennek  első  paraméterében  az  oszlop  azonosítóját,  míg  a  másodikban  a  beállítandó  hibaüzenetet  kell  átadnunk.                i  =  (Int32)dr["ID"];                if  (i  !=  1)                {                    dr.SetColumnError("ID",  "Csak  1-es                          azonosító  fogadható  el!");;                }Vizsgáljuk  a  sorokban  azt  is,  hogy  van-e  olyan  dátum  az  OrderDate  oszlopban,  melynek  hónapja  szeptembernél  nagyobb-e.  Ha  igen,  akkor  ott  is  hibajelzést  helyezünk  el.                d  =  (DateTime)dr["OrderDate"];                if  (d.Month  >=  9)                {                    dr.SetColumnError("OrderDate",  "Csak                            szeptember  előtti  időpont  fogadható                            el!");;                }            }            dataGrid6.DataSource  =  dt;        }DataGrid  cellájára  történő  kattintásAmikor  e  lap  DataGrid-jére  kattintunk,  akkor  a  következőket  tesszük:        private  void  dataGrid6_CurrentCellChanged(object              sender,  System.EventArgs  e)        {Egy  változóba  eltároljuk,  hogy  a  DataGrid-en  belül  hányas  sorszámú  sornál  történt  a  kattintás.            int  row  =  dataGrid6.CurrentCell.RowNumber;Ezt  követően  a  DataSet  második  adattáblájából  elővesszük  ezt  az  adatsort.            DataRow  dr  =                    ds1.Tables["Adattábla  2"].Rows[row];Majd  a  DataRow  osztály  RowError  property-jén  keresztül  megadunk  egy  üzenetet,  mely  most  az  aktuális  időpont  lesz.  Ezt  a  property-t  használhatjuk  fel  tehát  akkor,  ha  a  teljes  sorra  nézve  szeretnénk  üzenetet  megadni.  Ha  a  property  értékének  üres  sztringet  adunk  át,  azzal  töröljük  a  hibaüzenetet  és  így  a  DataGrid-ből  is  eltűnik  a  piros  ikon.            dr.RowError  =  DateTime.Now.ToString();A  listBox5-be  kigyűjtjük  a  hibás  adatokat  annál  a  sornál,  amelyik  cellában  épp  állunk  a  DataGrid-en  belül.  Ehhez  a  GetColumnsInError  függvényét  hívjuk  meg  a  DataRow  osztálynak,  mely  egy  DataColumn  osztályokat  tartalmazó  tömböt  ad  vissza.  Minden  DataColumn  egy-egy  oszlopot  ír  le.  A  tömbben  csak  azok  az  oszlopok  szerepelnek  az  adott  sorból,  melyeknél  már  beállítottunk  előzőleg  hibaüzenetet.            listBox5.Items.Clear();            foreach  (DataColumn  dc  in                  dr.GetColumnsInError())            {                listBox5.Items.Add(dc.ColumnName  +  ":  "  +                      dr[dc]);            }        }ClearErrors  gombA  sor  összes  előzőleg  beállított  hibáját  törölhetjük  a  ClearErrors  gombra  kattintva.        private  void  button16_Click_1(object  sender,              System.EventArgs  e)        {            try            {                DataTable  dt  =  ds1.Tables["Adattábla  2"];                int  row  =  dataGrid6.CurrentCell.RowNumber;                DataRow  dr  =  dt.Rows[row];Szükség  esetén  a  DataRow  osztály  HasErrors  property-jén  keresztül  megvizsgálhatjuk  azt  is,  hogy  az  adott  sor  tartalmaz-e  egyáltalán  hibát  vagy  sem.                if  (dr.HasErrors){Amennyiben  van  hiba  a  sorban,  akkor  a  ClearErrors  függvény  az  összest  törli.                    dr.ClearErrors();                }Annak  érdekében,  hogy  a  törölt  hibák  a  DataGrid-ből  is  eltűnjenek,  gondoskodnunk  kell  a  DataGrid  újrarajzolásáról  is.                dataGrid6.Refresh();            }            catch            {            }        }GetColumnError  gombEgy  hibát  nem  csak  beállíthatunk,  hanem  le  is  kérdezhetünk.  Ehhez  a  DataRow  osztály  GetColumnError  függvényét  kell  meghívnunk.  Paraméterként  annak  az  oszlopnak  a  nevét  kell  megadnunk,  amelyhez  tartozó  hibaüzenet  szövegére  vagyunk  kíváncsiak.        private  void  button17_Click(object  sender,              System.EventArgs  e)        {            try            {                DataTable  dt  =  ds1.Tables["Adattábla  2"];                int  row  =  dataGrid6.CurrentCell.RowNumber;                DataRow  dr  =  dt.Rows[row];                label3.Text  =  dr.GetColumnError("OrderDate");            }            catch            {            }        }6.  lap:  reláció  létrehozása  táblák  között  Példaprogram  hatodik  lapjaAdataink  mit  sem  érnek,  ha  nincs  közöttük  összefüggés.  Bármilyen  adatkezelő  rendszert  is  készítünk,  biztos  hogy  szükségünk  lesz  arra,  hogy  az  egyik  adattáblát  egy  másikhoz  kapcsoljuk.  A  reláció  létrehozása  így  nélkülözhetetlen  programozói  feladat.Mivel  a  DataSet-ben  már  létrehoztunk  két  táblát  és  mivel  mindkettőben  már  megtalálható  egy  olyan  azonos  típusú  oszlop,  mely  alapján  a  reláció  létrehozása  elvégezhető,  így  már  nem  marad  más  feladat  hátra,  mint  ennek  megvalósítása.Reláció  gombA  két  táblánkat  tegyük  most  ki  két  DataGrid  osztályba.        private  void  button18_Click(object  sender,              System.EventArgs  e)        {            DataTable  dt1  =  ds1.Tables["Adattábla  1"];            DataTable  dt2  =  ds1.Tables["Adattábla  2"];A  reláció  létrehozásához  a  két  tábla  ID  nevű  oszlopát  használjuk  fel.  Az  első  táblába  két  sort  helyeztünk  programunk  indulásakor  1-es  és  2-es  azonosítóval.  A  második  táblába  több  sort  vettünk  fel  1-es  és  szintén  több  sort  a  2-es  azonosítóból,  így  most  egy  a  többhöz  kapcsolatot  alakíthatunk  ki  e  két  tábla  között.  A  relációkat  a  DataSet  osztály  Relation  property-jén  keresztül  kezelhetjük.  Újat  létrehozni  az  Add  függvénnyel  tudunk.  Ennek  első  paramétere  a  reláció  tetszőleges  elnevezése  lesz.  Második  és  harmadik  paraméterében  azt  a  két  oszlopot  kell  megadnunk  a  két  adattáblánkból,  melyek  révén  azok  összekapcsolhatók.            ds1.Relations.Add("Reláció  1",                  dt1.Columns["ID"],  dt2.Columns["ID"]);Az  összekapcsolt  adatok  megjelenítésénél  fontos,  hogy  ne  a  DataSet-et  kössük  a  DataGrid-hez,  hanem  az  elsődleges  adattáblát.            dataGrid7.DataSource  =  dt1;        }A  DataGrid-ben  most  megjelenő  adatsorok  előtt  találunk  egy  +  jelet.  Erre  kattintva  kinyílik  egy  lista  és  linkek  formájában  látható  lesz  az  összes  elérhető  reláció.  Mivel  most  csupán  egy  darab  van,  így  csak  az.  A  linkre  kattintva  a  DataGrid  betölti  a  reláció  alapján  az  adott  sorhoz  tartozó  gyermek  sorokat  a  másik  adattáblából.  A  DataGrid  fejlécén  ekkor  megjelennek  a  szülő  adatsorának  adatai,  valamint  egy  új  gomb  is,  mellyel  visszaléphetünk  magára  a  szülő  adattáblára.GetChildRows  gombE  gombra  kattintva  meghívjuk  a  DataRow  osztály  GetChildRows  függvényét,  mely  képes  arra,  hogy  a  paraméterként  megadott  nevű  reláció  alapján  visszaadjon  egy  DataRow  osztályokat  tartalmazó  tömböt.  E  tömbben  azok  a  sorok  kapnak  helyet,  melyek  a  kiválasztott  szülő  sorhoz  tartozó  gyermek  sorok  a  megadott  reláció  alapján.        private  void  button19_Click(            object  sender,              System.EventArgs  e)        {            DataTable  dt  =  ds1.Tables["Adattábla  1"];            DataRow  dr  =  dt.Rows[0];            DataRow[]  rows  =                    dr.GetChildRows("Reláció  1");            listBox6.Items.Clear();Az  így  kapott  sorokat  egy  ciklus  segítségével  megjelenítjük  egy  ListBox-ban.            foreach  (DataRow  row  in  rows)            {                listBox6.Items.Add(                        row["ID"].ToString()  +                          "  -  "  +                          row["OrderDate"].ToString());            }        }ChildRelations  gombE  gomb  a  meglévő  relációkat  listázza  ki.  A  DataTable  osztály  ChildRelations  property-jében  egy  olyan  kollekciót  találunk,  melynek  minden  eleme  egy-egy  DataRelation  osztály  lesz,  amely  létrehozott  relációk  adatait  tárolja.        private  void  button20_Click(            object  sender,              System.EventArgs  e)        {            DataTable  dt  =  ds1.Tables["Adattábla  1"];            listBox6.Items.Clear();            foreach  (DataRelation  dr  in  dt.ChildRelations)            {A  létrehozásnál  megadott  reláció  nevét  a  RelationName  property-ből  tudhatjuk  meg,  míg  a  szülő  táblát  DataTable  osztály  formájában  elérhetjük  a  ParentTable  property-n  keresztül,  amelyhez  a  hozzá  tartozó  gyermek  táblát  a  ChildTable  property  szolgáltatja.                  listBox6.Items.Add(dr.RelationName);                listBox6.Items.Add(                    "    ParentTable:  "  +                      dr.ParentTable.TableName                );                listBox6.Items.Add(                    "    ChildTable:  "  +                      dr.ChildTable.TableName                );            }        }7.  lap:  oszlopok  bővítése,  számított  mezők,  összegzések  Példaprogram  hetedik  lapjaPéldaprogramunk  befejezéseképpen  a  7.  lapon  néhány  érdekes  funkciót  mutatunk  be,  mely  a  valós  életben  gyakran  igen  jól  használható.Columns.Add  gombE  gombra  kattintva  felveszünk  a  második  adattáblához  két  új  oszlopot.        private  void  button21_Click(object  sender,              System.EventArgs  e)        {            Random  r  =  new  Random();Az  első  oszlop  Double  típusú  lesz.            DataTable  dt  =  ds1.Tables["Adattábla  2"];            dt.Columns.Add("OrderCost",                  Type.GetType("System.Double"));A  második  oszlop  szintén  Double  típusú,  de  ennek  értékeit  nem  mi  adjuk  majd  meg,  hanem  egy  képlet  alapján  a  többi  oszlopban  lévő  aktuális  adatokat  figyelembe  véve,  automatikusan  kerül  majd  meghatározásra.            DataColumn  dc  =  new  DataColumn();            dc.ColumnName  =  "OrderTax";            dc.DataType  =  Type.GetType("System.Double");Az  oszlop  adatait  kiszámító  képletet  a  DataColumn  osztály  Expression  property-jébe  adhatjuk  meg  sztringként.  Itt  most  az  imént  létrehozott  OrderCost  oszlop  adatának  1,25-szörös  értékét  írjuk  majd  ezen  oszlop  adataihoz.            dc.Expression  =  "OrderCost  *  1.25";            dt.Columns.Add(dc);Az  első  új  oszlop  adatait  egy  ciklus  és  Random  osztály  véletlenszerűen  generált  számaival  töltjük  fel.            foreach  (DataRow  dr  in  dt.Rows)            {                dr["OrderCost"]  =  r.Next(1000)  /  10.0;            }            dataGrid8.DataSource  =  dt;        }Compute  gombAmikor  a  Compute  gombra  kattintunk,  akkor  a  DataTable  osztály  azonos  nevű  függvényét  hívjuk  meg,  mely  képes  az  adattáblában  egyszerű  műveletek  elvégzésére  az  adatoszlopokon,  mint  például  az  összeg  számítás,  maximum,  minimum  meghatározása,  stb.A  Compute  függvény  első  paraméterében  az  elvégzendő  műveletet  kell  leírnunk,  míg  a  második  esetben  egy  szűrő  feltétel  adható  meg  az  adattáblában  található  sorokra.  Ha  a  második  paraméterben  egy  üres  sztringet  adunk  meg,  akkor  az  elvégzendő  műveletben  az  adattábla  minden  egyes  sora  részt  vesz.        private  void  button22_Click(object  sender,              System.EventArgs  e)        {            DataTable  dt  =  ds1.Tables["Adattábla  2"];            label4.Text  =  "ID  1  =  "  +  dt.Compute(                  "sum(OrderCost)",  "ID  =  1").ToString()  +                    Environment.NewLine;            label4.Text  +=  "ID  2  =  "  +  dt.Compute(                  "sum(OrderCost)",  "ID  =  2").ToString()  +                    Environment.NewLine;            label4.Text  +=  "All  =  "  +  dt.Compute(                  "sum(OrderCost)",  "").ToString()  +                    Environment.NewLine;        }ÖsszefoglalásFentiekben  áttekinttettünk  a  teljesség  igénye  nélkül  néhány  igen  fontos  mozzanatot  az  ADO.NET  világából.  Ezen  ismeretekre  alapozva  már  nekiláthatunk  komolyabb  tudás  megszerzésére,  mellyel  maximálisan  kihasználhatjuk  a  .NET  Framework  adta  lehetőségeket  az  adatbányászat  során.Prethus  Gábor