C# - Adatfrissítés DataTable objektummal

forráskód letöltése
Adatbázisokkal történő munka során igencsak lelassítja az alkalmazást, ha minden művelet után frissítenénk az adatforrás tartalmát. Különösen igaz ez nagy mennyiségű adat egyidejű kezelésekor. Ennek elkerülésére a .NET Framework objektumainak segítségével a memóriában szerkeszthetjük adatainkat, majd egy mozdulattal frissíthetjük a fizikai adatforrást, a megfelelő metódussal. Ezt a mechanizmust járjuk most körül cikkünkben egy gyakorlati példa segítségével.
A példához szükséges a SampleDB adatbázis, melyet a mellékelt Run.cmd BATCH állomány lefuttatásával hozhatunk létre. Csak arra kell ügyelni, hogy a SampleDB.sql parancsállomány a BATCH állománnyal azonos mappában legyen. A SampleDB.sql parancsállomány 5. sorában adja meg helyesen a létrehozandó adatbázisfájlok mappájának nevét és elérési útvonalát.
Áttekintés
A példában egy DataTable objektumba töltjük be a SampleDb adatbázis Table1 táblájának adatait, melyen a Form kontroljainak segítségével műveleteket végezhetünk. Használhatnánk DataSet objektumot is, azonban itt egy táblával dolgozunk, nincs szükség több tábla tárolására. Szükség szerint új rekordokat szúrhatunk be a DataTable objektumba, rekordokat törölhetünk, illetve frissíthetünk a táblában. Az „Adatbázis frissítése” gomb segítségével a DataTable tartalmát egy mozdulattal kiírhatjuk a fizikai adatforrásba.
A DataTable objektumok végső soron cache-ként viselkednek, amelyeknél az adatmódosítás és az adatfrissítés művelete elválik egymástól. A memóriabeli objektumokban tartva és ott szerkesztve adatainkat megtakaríthatjuk az állandó adatbázis-kapcsolat létesítésének, és a DML műveletek elvégzésének idejét.
Adataink frissítése a memóriabeli objektumból a fizikai adattáblába kétlépéses folyamat. Az első lépésben elvégezzük az adatmódosító utasításokat (INSERT/DELETE/UPDATE) a memóriabeli blokkon, majd ezzel az adathalmazzal frissítjük a fizikai adathalmazt. Általában ezt úgy tesszük meg, hogy meghívjuk egy adapter – kapcsolattól függően SqlDataAdapter vagy OleDbDataAdapter - objektum Update metódusát, a megfelelő paraméterrel. Bizonyos beállításokat azonban meg kell tennünk annak érdekében, hogy a frissítés valóban megtörténjen, és az adatok konzisztenciáját megőrizzük. Ezeket a lépéseket ismertetjük a következőkben.
Rekordok beszúrása a DataTable objektumba
A rekordok beszúrásának módja egy új DataRow objektum létrehozása, melynek mezőit feltöltjük a Form-on megadott adatokkal.
DataRow dr = dt.NewRow();
Meghatározzuk az utolsó rekord azonosítóját, majd egy ennél eggyel nagyobb értéket adunk meg az új rekord azonosítójául.
int id = Convert.ToInt32(dt.Rows[dt.Rows.Count-1][0]) + 1;
dr[0] = id;
Végül megadjuk a szövegmezőben megadott karakterláncokat a másik két oszlop adataiként.
dr[1] = textBox1.Text;
dr[2] = textBox2.Text;
dt.Rows.Add(dr);
...
Ekkor tehát egy új rekord került a DataTable objektumba, sajátos állapotjelzővel, melynek értéke fontos lesz az adatfrissítés procedúrájában. Minden rekord rendelkezik egy RowState tulajdonsággal, melynek értéke attól függ, hogy milyen műveletet végeztünk el a rekordon éppen.
RowState
Osztály: DataTable
public DataRowState RowState {get;}
A property értékei egy felsorolt típus elemei, melynek neve DataRowState. Elemei pedig a következők:
Érték Magyarázat
Added A rekord beszúrásra került a DataTable objektumba, de az AcceptChanges metódus még nem hívódott meg.
Deleted A rekord törlésre került az objektumból.
Detached A sor elkészült, de nem lett része a DataRowCollection gyűjteménynek. Ez az állapot köztes állapot a létrehozás és a kollekcióba-sorolás közt.
Modified A rekord módosult, de az AcceptChanges metódus még nem hívódott meg.
Unchanged A rekord értékeiben nem történt változás az AcceptChanges meghívása óta.
A DataTable objektum felhasználásával történő frissítés során minden rekord állapota vizsgálatra kerül, és ahol valamilyen változás történt, ott lefut az adott változást reprezentáló SQL-utasítás, elvégezve a módosítást a fizikai táblán.
Rekordok módosítása
A DataTable objektum rekordjainak módosításakor megvizsgáljuk a rekordokat, megkeressük a megadott azonosítóval rendelkező rekordot, majd módosítjuk a kívánt mezőt.
for(int i=0;i<dt.Rows.Count;i++)
{
  if (dt.Rows[i][0].ToString() == comboBox2.Text)
  {
Amely mező nem marad üresen az UPDATE fül alatt, az a mező felhasználásra kerül az új érték megadásakor. Amennyiben nem szeretnénk az egyik mezőt módosítani, hagyjuk üresen a szövegdobozt.
    if (textBox3.Text != "")
    {
      dt.Rows[i][1] = textBox3.Text; 
      textBox3.Text = "";
    }
    if (textBox4.Text != "")
    {
      dt.Rows[i][2] = textBox4.Text; 
      textBox4.Text = "";
    }
  }
}
Rekordok törlése
A rekordok törlésekor is megkeressük a megadott azonosítóval rendelkező sort, majd az adott rekord Delete metódusával töröljük azt a DataTable objektum gyűjteményéből. A Delete metódust használjuk a RemoveAt metódus helyett, mivel csak ez a metódus törli a rekordot a táblából, és állítja be a RowState tulajdonságot Deleted értékűre. A frissítő metódus ugyanis ezt figyeli, ahogy később látni fogjuk.
for(int i=0;i<dt.Rows.Count;i++)
{
  if (dt.Rows[i][0].ToString() == comboBox1.Text)
  {
    dt.Rows[i].Delete();          
  }
}
Adatok frissítése
A fizikai adattábla tehát akkor még nem tartalmazza a változásokat. Ennek érdekében létrehozunk egy SqlCommandBuilder objektumot a SqlDataAdapter objektum metódusainak előállításához.
builder = new SqlCommandBuilder(ad);
Nagyon fontos momentum, hogy a SampleDb Table1 oszlopát a megfelelő SQL utasítással hozzuk létre, mert egyébként a SqlCommandBuilder objektum nem ad megfelelő értéket. A lényeg, hogy a tábla tartalmazzon egy elsődleges kulcs oszlopot, melyet az objektum felhasznál az utasítások generálásához.
CREATE TABLE [Table1]
(
  [ID] [int] NOT NULL ,
  [Name] [varchar] (100) NOT NULL,
  [Position] [varchar] (100) NOT NULL,
  CONSTRAINT PK_Products PRIMARY KEY CLUSTERED(ID) 
) ON [PRIMARY]
GO
A rekordok beszúrásához, frissítéséhez, valamint törléséhez egy-egy SQL-utasításra van szükség. Ezeket a SqlCommandBuilder megfelelő metódusaival generálhatjuk. A generált értékek SqlCommand objektumok, melyeknek CommandText property-je tartalmazza az SQL utasítást.
ad.DeleteCommand = builder.GetDeleteCommand();
ad.InsertCommand = builder.GetInsertCommand();
ad.UpdateCommand = builder.GetUpdateCommand();
Az utasítások közül egy a következőképpen fest:
INSERT INTO TABLE1(ID , NAME , POSITION)
VALUES (@p1, @p2, @p3)
A SqlDataAdapter objektum Update objektumát hívjuk meg ezek után, frissítendő a fizikai adathalmazt.
ad.Update(dt);
A frissítést végző gomb lenyomása után a Form negyedik füle alatt megnézhetjük az adattábla pontos tartalmát.