C# - Adattábla módosítása programból

forráskód letöltése
Mostani cikkünkben nem csak az adatok megjelenítésével foglalkozunk, hanem azok módosítási lehetőségével is. Így egy lekérdezés eredménye szerkeszthetővé válik néhány TextBox-on keresztül.
Első lépésként egy szokásos kapcsolatot építünk ki az MS SQL Northwind adatbázisával. Mellékelt példa használatához adja meg a szerver nevét, valamint a bejelentkező nevet és jelszót.
    private void button1_Click(object sender, System.EventArgs e)
    {
      connection = new SqlConnection("Data Source="+textBox1.Text+";uid="+textBox2.Text+";password="+textBox3.Text+";initial catalog=Northwind;Connect Timeout=3");
      connection.Open();
Amint az adatbázis kapcsolat adott, futtatunk egy igen egyszerű lekérdezést a Products táblára, melynek eredményét egy DataSet-ben tároljuk.
      da = new SqlDataAdapter("select * from Products", connection);
      da.Fill(ds, "Products");
A tábla egyes oszlopait hozzákötjük egy-egy TextBox-hoz, illetve a termékek azonosítóját egy Label-hez, hogy az ne váljon szerkeszthetővé.
      label1.DataBindings.Add("Text", ds, "Products.ProductID");
      textBox4.DataBindings.Add("Text", ds, "Products.ProductName");
      textBox5.DataBindings.Add("Text", ds, "Products.QuantityPerUnit");        
Amikor változik az aktuális rekord pozíció a táblában, akkor erről kérhetünk egy eseményt a BindingContext-től. Ehhez csak annyi a teendőnk, hogy a PositionChanged eseményhez hozzárendeljünk egy eseménykezelő eljárást, mely meghívásra kerül minden olyan esetben, amikor a rekord pozíció változik.
      this.BindingContext[ds, "Products"].PositionChanged += new System.EventHandler(DoPositionChanged);
Ez az eseménykezelő függvény a DoPositionChanged belső függvényünk lesz. Ennek feladata, hogy kiírja az aktuális rekord sorszámát a StatusBar-ra. Ezt a függvényt most rögtön meg is hívjuk, hogy aktualizáljuk a kiírást.
      DoPositionChanged(null, null);
      ...
   }
Nézzük, hogy is történik ez a kiírás. A BindingContext adott elemének Position property-jéből olvashatjuk ki az aktuális rekord sorszámát. Ez a sorszám nullától indul, tehát az első rekord a nulladik sorszámú.
      private void DoPositionChanged(object sender, System.EventArgs e) 
      {
          statusBarPanel1.Text = "Row: " + (this.BindingContext[ds, "Products"].Position + 1);
      }
Tegyünk egy kis kitérőt és nézzük is meg, hogy mit takar a BindingContext[ds, "Products"] kifejezés. Bár ránézésre érthető, hogy e kifejezés az adott DataSet-en belüli Products táblát adja, nézzük, hogy milyen típusú objektumokról is van szó.
A BindingContext osztálynak van egy Item nevű property-je, melynek két változata is létezik. Ez a property egy tömb, melynek minden eleme ListManager osztályt tartalmaz. A property egyik változata esetén csak a DataSet-et kell megadni, másik esetben még egy sztringet is, melyben a tábla nevét adhatjuk meg. Így a BindingContext[ds, "Products"] használata esetén valójában a BindingContext.Item[ds, "Products"] kifejezést használjuk.
Nézzük most, hogy a ListManager osztály milyen tulajdonságokkal rendelkezik.
A Position property-vel már találkoztunk, ez adja meg az aktuális rekord pozíciót, sőt ezzel állíthatjuk is azt.
    private void button3_Click(object sender, System.EventArgs e)
    {
      if (this.BindingContext[ds, "Products"].Position>0)
      {
        this.BindingContext[ds, "Products"].Position--;        
      }        
    }
A másik lényeges kérdés, hogy hány eleme, rekordja is van az adott táblának. Ehhez a Count property használatára lesz szükségünk, mely ezt a számot tárolja.
    private void button4_Click(object sender, System.EventArgs e)
    {
      if (this.BindingContext[ds, "Products"].Position<this.BindingContext[ds, "Products"].Count-1)
      {
        this.BindingContext[ds, "Products"].Position++;
      }        
    }
A Current property az aktuális elemet adja vissza object típusban. Például, ha az adatforrás DataView vagy DataTable típusú, akkor erre a property-re nyugodtan rádefiniálhatjuk a DataRowView osztályt, mivel ez esetben ilyen típusban kerül visszaadásra a Current.
A DataSource property-ben érhető el a ListManager által kezelt adatforrás, mely a következők közül kerülhet ki:
  • DataTable
  • DataView
  • DataSet
  • DataSetView
  • Egy dimenziós tömb
  • Bármilyen komponens, melyben felhasználásra került az IListSource interface
  • Bármilyen komponens, melyben felhasználásra került az IList interface
Mostani példánkban az egyes mezőket TextBox-okhoz kötöttük. Mivel ezek eleve szerkeszthetőek, így az adattartalom rajtuk keresztül megváltoztatható. Viszont hiába írunk bármit a TextBox-okban, az csak az aktuális DataSet-ben okoz változást, de az adatbázisunk tartalma változatlan marad. Ahhoz, hogy a végrehajtott változtatások bekerüljenek a táblába, meg kell hívnunk az SqlDataAdapter osztályunk Update függvényét, melynek paraméterül átadjuk az aktuális DataSet-et, melyben a megváltozott adatok vannak, valamint a tábla nevét, mely jelen esetben a Products lesz.
Ha viszont csak ennyit tennénk, akkor előfordulhat olyan eset, hogy a TextBox-ban épp szerkesztés alatt álló adat még nem került a DataSet-be sem, így ez nem kerül vissza az adatbázisba se, ami nyilván hibás adatrögzítéshez vezet. Történhet ez olyankor, ha az egyik TextBox-ban átírjuk az ott lévő adatot, majd rögtön az Update-t hívjuk. Ekkor az adott rekord adott mezője még szerkesztési üzemmódban van, így annak új tartalma még nem került be a DataSet-be. Elkerülendő ezt a hibát, meghívjuk még az Update előtt a ListManager EndCurrentEdit nevű függvényét, mellyel kényszerítjük, hogy a szerkesztés befejezésre kerüljön és a megváltozott tartalom mentve legyen a DataSet-be, ahonnan majd az Update hívása visszajuttatja az adattáblába.
    private void button2_Click(object sender, System.EventArgs e)
    {
      this.BindingContext[ds, "Products"].EndCurrentEdit();
      da.UpdateCommand = new SqlCommand("UPDATE Products SET ProductName = '" + textBox4.Text + "', QuantityPerUnit='"+textBox5.Text+"' WHERE (ProductID = "+label1.Text+")", connection);
      da.Update(ds, "Products");
    }
Ha az aktuális szerkesztést visszavonni szeretnénk, akkor használhatjuk az EndCurrentEdit helyett a CancelCurrentEdit függvényt.
Új elemet is létrehozhatunk a ListManager AddNew függvényének hívásával.
    private void button5_Click(object sender, System.EventArgs e)
    {
      this.BindingContext[ds, "Products"].AddNew();
    }
A RemoveAt függvény segítségével pedig törölhetünk egy-egy elemet a listából. Ehhez paraméterként a törlendő elem sorszámát kell megadnunk.