Grafikus C# – Windows Forms tanfolyam › 3.6 lecke Windows Forms · 3.6 lecke · adatok módosítása Eddig főleg olvastad az adatbázist. Egy valódi nyilvántartásban viszont új sorokat is felveszel, a meglévőket javítod, és a feleslegeseket törlöd. Ebben a leckében a három módosító SQL utasítást tanulod meg, és egy dolgozószerkesztő ablakot építesz, amelyben a táblázat egy sorára kattintva a mezők kitöltődnek, a gombok pedig mentenek, vagy törölnek.INSERT, UPDATE és DELETE – adatok felvétele, módosítása és törlése

A lecke végére
- az
INSERT, azUPDATEés aDELETEutasítást helyesen,WHEREfeltétellel használod; - tudod, mi történik, ha a
WHEREkimarad, és hogyan védekezz a DB Browserben (Revert Changes); - az
ExecuteNonQueryvisszatérési értékéből (az érintett sorok száma) megállapítod, sikerült-e a művelet; - az új sor azonosítóját a
LastInsertRowIdadja meg; - a hiányzó értéket
DBNull.Valuealakban mented (NULL); - a táblázat kijelölését az ablak mezőivel összekötöd, és a törlést megerősítéssel védi.
Mielőtt elkezded
Ehhez a leckéhez kell a 3.5 lecke projektje (DB.cs, az adatok tábla a 9 sorral), a paraméterezett lekérdezés (3.3 lecke), a DataGridView (3.4 lecke) és a bool visszatérésű metódus (1.11 lecke).
A három módosító utasítás
-- új sor felvétele
INSERT INTO adatok (vnev, knev, fizetes, cim)
VALUES ('Fekete', 'Dóra', 390000, 'Győr');
-- meglévő sor módosítása: a WHERE adja meg, melyiket
UPDATE adatok
SET fizetes = 420000, cim = 'Veszprém'
WHERE id = 3;
-- sor törlése: a WHERE adja meg, melyiket
DELETE FROM adatok
WHERE id = 3;id-t az adatbázis adja (automatikus számozás).id) a legbiztonságosabb feltétel, mert egyetlen sort azonosít. A név nem jó, mert lehet két azonos nevű dolgozó.Jósolj!
Az UPDATE adatok SET cim = 'Győr' WHERE id = 99 utasítást futtatod, de nincs 99-es azonosítójú sor. Hibát kapsz? Hány sor módosul?
Jóslat ellenőrzése
Nem kapsz hibát, és nulla sor módosul. Az SQL szempontjából az utasítás érvényes: a feltételnek egyetlen sor sem felel meg, ezért nincs mit módosítani. Ezért fontos, hogy a C# program ellenőrizze az érintett sorok számát (az ExecuteNonQuery visszatérési értékét), és ne higgye el, hogy a módosítás sikerült, csak mert nem keletkezett kivétel.
A WHERE védelme: mi történik nélküle?
WHERE nélkül minden sor érintett!
Az UPDATE adatok SET fizetes = 0 utasítás minden dolgozó fizetését nullára állítja, a DELETE FROM adatok pedig a teljes táblát kiüríti. Az SQLite nem kérdez, és nincs „Visszavonás” gomb. A hiba az egyik leggyakoribb és legdrágább.
Szerencsére a DB Browser védelmet ad: minden módosítás csak átmenetileg érvényes, amíg ki nem írod a változásokat (Write Changes, Ctrl+S). Ha elrontottál valamit, a Revert Changes gomb eldobja az utolsó írás óta történt összes módosítást. Próbáld ki biztonságosan:
- Futtasd az Execute SQL lapon:
UPDATE adatok SET fizetes = 0; - Nézd meg a Browse Data lapon az
adatoktáblát: mindenkinek nulla a fizetése. - Kattints a Revert Changes gombra: a fizetések visszaállnak.
A jó szokás a próbálkozás sorrendje: a törlés vagy módosítás előtt futtasd ugyanazt a WHERE feltételt egy SELECT-tel, és nézd meg, mely sorokat érinti. Csak ha jó, írd át UPDATE-re vagy DELETE-re.
-- 1. előnézet: mely sorokat érintene?
SELECT * FROM adatok WHERE cim = 'Pécs' AND fizetes < 400000;
-- 2. ha jó, ugyanaz a feltétel a törléshez
DELETE FROM adatok WHERE cim = 'Pécs' AND fizetes < 400000;Mit tegyél ide: a DB Browser ablaka, amelyben a Write Changes és a Revert Changes gomb látszik (a változtatás után aktívak).Javasolt fájlnév: winforms-3-6-revert.webp · Alt szöveg: A DB Browser Write Changes és Revert Changes gombja
A módosító metódusok a DB osztályban
A három művelet a DB.cs osztályba kerül. A felhasználó adatai paraméterként mennek (3.3 lecke). Az ExecuteNonQuery az érintett sorok számát adja vissza, amelyből eldönthetjük, sikerült-e a művelet. A felvételnél a LastInsertRowId megadja az új sor azonosítóját:
// üres cím helyett NULL kerül az adatbázisba
private static object CimErtek(string cim)
{
if (cim.Length == 0)
{
return DBNull.Value;
}
return cim;
}
public static long DolgozoFelvetel(string vnev, string knev, int fizetes, string cim)
{
using (SQLiteConnection kapcsolat = UjKapcsolat())
{
kapcsolat.Open();
string sql = "INSERT INTO adatok (vnev, knev, fizetes, cim) VALUES (@vnev, @knev, @fizetes, @cim)";
using (SQLiteCommand parancs = new SQLiteCommand(sql, kapcsolat))
{
parancs.Parameters.AddWithValue("@vnev", vnev);
parancs.Parameters.AddWithValue("@knev", knev);
parancs.Parameters.AddWithValue("@fizetes", fizetes);
parancs.Parameters.AddWithValue("@cim", CimErtek(cim));
parancs.ExecuteNonQuery();
}
return kapcsolat.LastInsertRowId;
}
}
public static bool DolgozoModositas(int id, string vnev, string knev, int fizetes, string cim)
{
using (SQLiteConnection kapcsolat = UjKapcsolat())
{
kapcsolat.Open();
string sql = "UPDATE adatok SET vnev = @vnev, knev = @knev, fizetes = @fizetes, cim = @cim WHERE id = @id";
using (SQLiteCommand parancs = new SQLiteCommand(sql, kapcsolat))
{
parancs.Parameters.AddWithValue("@vnev", vnev);
parancs.Parameters.AddWithValue("@knev", knev);
parancs.Parameters.AddWithValue("@fizetes", fizetes);
parancs.Parameters.AddWithValue("@cim", CimErtek(cim));
parancs.Parameters.AddWithValue("@id", id);
int erintett = parancs.ExecuteNonQuery();
return erintett == 1;
}
}
}
public static bool DolgozoTorles(int id)
{
using (SQLiteConnection kapcsolat = UjKapcsolat())
{
kapcsolat.Open();
using (SQLiteCommand parancs = new SQLiteCommand("DELETE FROM adatok WHERE id = @id", kapcsolat))
{
parancs.Parameters.AddWithValue("@id", id);
return parancs.ExecuteNonQuery() == 1;
}
}
}
public static DataTable Osszes()
{
DataTable tabla = new DataTable();
using (SQLiteConnection kapcsolat = UjKapcsolat())
{
kapcsolat.Open();
using (SQLiteDataAdapter adapter = new SQLiteDataAdapter("SELECT id, vnev, knev, fizetes, cim FROM adatok ORDER BY vnev, knev", kapcsolat))
{
adapter.Fill(tabla);
}
}
return tabla;
}long típusú szám, ezért a metódus is long értéket ad.NULL értékének C# megfelelője. Az üres szöveg és a NULL különbözik: üres cím helyett NULL kerül az adatbázisba, így később az IS NULL működik.DBNull.Value értéket vagy a szöveget adja. A visszatérési típus object, mert a kétféle érték közös típusa az.Jósolj!
Egy dolgozót a DolgozoTorles(5) hívással töröltél. Ismét meghívod a DolgozoTorles(5) metódust. Mit ad vissza másodszor? Dob-e kivételt?
Jóslat ellenőrzése
false értéket ad, és nem dob kivételt: a törlés végrehajtódik, de nulla sort érint, ezért ExecuteNonQuery() == 1 hamis. A hívó program így tudja, hogy nem történt valódi törlés, és érthető üzenetet adhat.
Az ablak: kijelölés és szerkesztőmezők
Az ablakon a táblázat mellett a szerkesztés mezői állnak:
ReadOnly: True, AllowUserToAddRows: False, MultiSelect: False, SelectionMode: FullRowSelect).Maximum: 10000000, Increment: 10000).btnMent felirata a helyzethez igazodik.A programnak két helyzetet kell megkülönböztetnie: új dolgozót veszünk fel (INSERT), vagy egy meglévőt módosítunk (UPDATE). Ezt egy kijeloltId mező mondja meg: 0 az új dolgozót, a nullánál nagyobb szám a szerkesztett sor azonosítóját jelenti.
private int kijeloltId = 0;
private bool frissites = false;
private void Uzenet(string szoveg, bool hiba)
{
lblUzenet.Text = szoveg;
lblUzenet.ForeColor = hiba ? Color.Firebrick : Color.SeaGreen;
}
private void Uj()
{
kijeloltId = 0;
txtVnev.Clear();
txtKnev.Clear();
txtCim.Clear();
nudFizetes.Value = 0;
btnMent.Text = "Új dolgozó felvétele";
txtVnev.Focus();
}
private void MezokTolt()
{
if (dgvDolgozok.CurrentRow == null)
{
return;
}
DataGridViewRow sor = dgvDolgozok.CurrentRow;
kijeloltId = Convert.ToInt32(sor.Cells["id"].Value);
txtVnev.Text = Convert.ToString(sor.Cells["vnev"].Value);
txtKnev.Text = Convert.ToString(sor.Cells["knev"].Value);
txtCim.Text = Convert.ToString(sor.Cells["cim"].Value);
object fizetes = sor.Cells["fizetes"].Value;
nudFizetes.Value = fizetes == DBNull.Value ? 0 : Convert.ToDecimal(fizetes);
btnMent.Text = "Módosítás mentése";
}
private void dgvDolgozok_SelectionChanged(object sender, EventArgs e)
{
if (!frissites)
{
MezokTolt();
}
}
private void SorKijelolese(int id)
{
foreach (DataGridViewRow sor in dgvDolgozok.Rows)
{
if (Convert.ToInt32(sor.Cells["id"].Value) == id)
{
dgvDolgozok.CurrentCell = sor.Cells["vnev"];
sor.Selected = true;
return;
}
}
}
private void Frissit(int kijelolendoId)
{
frissites = true;
try
{
dgvDolgozok.DataSource = DB.Osszes();
dgvDolgozok.Columns["vnev"].HeaderText = "Vezetéknév";
dgvDolgozok.Columns["knev"].HeaderText = "Keresztnév";
dgvDolgozok.Columns["fizetes"].HeaderText = "Fizetés (Ft)";
dgvDolgozok.Columns["cim"].HeaderText = "Város";
SorKijelolese(kijelolendoId);
}
catch (Exception ex)
{
MessageBox.Show("Nem sikerült betölteni a listát: " + ex.Message);
}
finally
{
frissites = false;
}
}
private void Form1_Load(object sender, EventArgs e)
{
Uj();
Frissit(0);
}INSERT vagy UPDATE kell.DBNull értéket üres szöveggé alakítja, így a NULL című sor nem okoz hibát. A Convert.ToDecimal(DBNull.Value) viszont hibát dobna, ezért a fizetésnél külön ellenőrzünk.DataSource beállítása közben a táblázat kijelölése többször változik, és minden változás kiváltaná a SelectionChanged eseményt. A jelző ilyenkor leállítja a felesleges mezőtöltést (2.11 lecke).Mentés és törlés a gombokból
private void btnUj_Click(object sender, EventArgs e)
{
dgvDolgozok.ClearSelection();
Uj();
Uzenet("", false);
}
private void btnMent_Click(object sender, EventArgs e)
{
string vnev = txtVnev.Text.Trim();
string knev = txtKnev.Text.Trim();
string cim = txtCim.Text.Trim();
int fizetes = (int)nudFizetes.Value;
if (vnev.Length == 0 || knev.Length == 0)
{
Uzenet("A vezeték- és a keresztnév kötelező!", true);
return;
}
try
{
if (kijeloltId == 0)
{
long ujId = DB.DolgozoFelvetel(vnev, knev, fizetes, cim);
Uzenet("Az új dolgozó felvéve.", false);
Frissit((int)ujId);
MezokTolt();
}
else
{
if (DB.DolgozoModositas(kijeloltId, vnev, knev, fizetes, cim))
{
Uzenet("A módosítás mentve.", false);
Frissit(kijeloltId);
}
else
{
Uzenet("A dolgozó nem található (közben törölték?).", true);
Frissit(0);
}
}
}
catch (Exception ex)
{
MessageBox.Show("Adatbázis-hiba: " + ex.Message);
}
}
private void btnTorol_Click(object sender, EventArgs e)
{
if (kijeloltId == 0)
{
Uzenet("Előbb válassz ki egy dolgozót a táblázatból!", true);
return;
}
DialogResult valasz = MessageBox.Show(
$"Biztosan törlöd: {txtVnev.Text} {txtKnev.Text}? A művelet nem vonható vissza.",
"Törlés",
MessageBoxButtons.YesNo,
MessageBoxIcon.Warning);
if (valasz != DialogResult.Yes)
{
return;
}
try
{
if (DB.DolgozoTorles(kijeloltId))
{
Uzenet("A dolgozó törölve.", false);
}
else
{
Uzenet("A dolgozó már nem létezett.", true);
}
Frissit(0);
Uj();
}
catch (Exception ex)
{
MessageBox.Show("Adatbázis-hiba: " + ex.Message);
}
}INSERT. Egyébként UPDATE a kijelölt azonosítóval.long) int típusra alakítjuk, hogy a SorKijelolese megtalálja. Az azonosítók ebben a kis táblában belefér az int tartományába.MessageBox kérdése megvédi a felhasználót. A felirat tartalmazza a törlendő nevet, így látja, mit töröl.MessageBox).Jósolj!
Rákattintasz egy dolgozóra, majd a Új dolgozó gombra, és beírsz egy nevet. A Mentés gombbal mentesz. INSERT vagy UPDATE fut le? Mi lenne, ha az Uj() metódus nem nullázná a kijeloltId mezőt?
Jóslat ellenőrzése
Az INSERT fut le, mert az Uj() a kijeloltId értékét nullára állította. Ha ez kimaradna, a program a korábban kijelölt dolgozó azonosítójával UPDATE utasítást futtatna, és az új név felülírná a meglévő dolgozó adatait. Ezért kell az Uj() metódusnak mindig nullázni a jelzőt.
Mit tegyél ide: a futó szerkesztő: a táblázatban egy kijelölt sor, a mezők kitöltve, a „Módosítás mentése” és a Törlés gomb, a zöld „A módosítás mentve.” üzenet.Javasolt fájlnév: winforms-3-6-szerkeszto.webp · Alt szöveg: A dolgozószerkesztő egy kijelölt dolgozóval
Hibakeresés: te vagy a hibadetektív
Mi a baj, és hogyan javítod?
Gondold végig az okot, és csak utána nyisd le a megoldást.
1. Mindenkinek ugyanaz lett a város
UPDATE adatok SET cim = @cimHiba és javítás
Hiányzik a WHERE id = @id, ezért az utasítás minden sort módosít. Ha ez véletlenül megtörtént, az éles adatbázisban nincs visszaút, a DB Browserben a Revert Changes még segít, ha nem írtad ki a változtatást. Mindig tedd a WHERE feltételt az UPDATE és a DELETE végére, és előbb próbáld ki SELECT-tel.
2. A mentés új sort hoz létre a módosítás helyett
Egy meglévő dolgozó nevét átírod, mentesz, és a táblázatban két sor jelenik meg. A program Ok és javítás
INSERT utasítást futtat az UPDATE helyett. Ellenőrizd, hogy a kijeloltId a sor kijelölésekor beállítódik-e (a MezokTolt() metódusban), és hogy a SelectionChanged esemény a táblázathoz van-e kötve a tervezőben (Events nézet).
3. A módosítás után más sor lesz kijelölve
Mentés után a táblázat első sora kerül kijelölésre, és a mezők a másik dolgozó adatait mutatják. A Ok és javítás
Frissit() újra betölti a táblázatot, és a kijelölés elveszik. A megoldás: az azonosítót tovább kell adni a Frissit(kijeloltId) hívásnak, amely a SorKijelolese(id) segítségével az azonosító alapján újra kijelöli a sort.
4. InvalidCastException a NULL címnél
nudFizetes.Value = (decimal)sor.Cells["fizetes"].Value;Hiba és javítás
Ha a fizetés NULL az adatbázisban, a cella értéke DBNull.Value, amelyet nem lehet decimal típusra alakítani. Előbb vizsgáld meg: fizetes == DBNull.Value ? 0 : Convert.ToDecimal(fizetes). A szövegmezőknél a Convert.ToString elintézi a DBNull értéket.
5. A rossz sor törlődik
DB.DolgozoTorles(dgvDolgozok.CurrentRow.Index + 1);Hiba és javítás
A sor sorszáma a táblázatban nem azonos az adatbázis azonosítójával: a rendezés, a törlések és a szűrés után eltérnek. A törlésnél mindig az azonosítót (az id oszlop értékét) használd: DB.DolgozoTorles(kijeloltId).
6. A módosítás nem látszik az adatbázisban
A programban a módosítás látszik, de a DB Browserben nem. A DB Browser a fájl régi állapotát mutatja. Zárd be és nyisd meg újra az adatbázist, vagy kattints a Refresh gombra a Browse Data lapon. Ha a DB Browserben van ki nem írt változtatás (Ok és javítás
Write Changes hiányzik), a C# program database is locked hibát kaphat. Írd ki a változtatásokat (Ctrl+S), vagy zárd be a DB Browsert, amíg a programot futtatod.
Mini projekt: dolgozó-nyilvántartó
Állítsd össze a teljes nyilvántartót:
- Az
adatoktábla a 3.5 leckéből (9 sorral), aDB.csosztály a három módosító metódussal és azOsszes()metódussal. - Az ablak a táblázattal, a négy mezővel, az Új, Mentés és Törlés gombbal és az üzenet-felirattal.
- A kijelölés betölti a mezőket, a Mentés dönt az
INSERTés azUPDATEközött, a Törlés megerősítést kér. - Új követelmény: a fizetés ne lehessen negatív, és a nevek legfeljebb 40 karakteresek legyenek (
MaxLength). Hiba esetén a program ne mentsen, és jelezzen. - Tesztelj: új sor üres címmel (NULL), a cím törlése egy meglévő soron, módosítás utáni kijelölés, törlés és újratöltés, a program újraindítása.
Megoldás megnyitása (próbáld ki előbb önállóan!)
A teljes kód a leckében szerepel (DB.cs, Form1.cs). A negatív fizetést a NumericUpDown Minimum tulajdonsága (0) kizárja, ezért külön kódot sem kell írni. A hosszkorlátot a MaxLength tulajdonság teszi lehetővé mindhárom szövegmezőn. Ha ezeket kihagynád a tervezőből, az ellenőrzés a btnMent_Click elején történne:
if (vnev.Length > 40 || knev.Length > 40 || cim.Length > 40)
{
Uzenet("A nevek és a város legfeljebb 40 karakteresek lehetnek!", true);
return;
}
if (fizetes < 0)
{
Uzenet("A fizetés nem lehet negatív!", true);
return;
}Mit tegyél ide: a kész nyilvántartó, amelyben a táblázat az összes dolgozót mutatja, az egyik sor kijelölve, és a mezők kitöltve.Javasolt fájlnév: winforms-3-6-kesz.webp · Alt szöveg: A kész dolgozó-nyilvántartó
Három önálló gyakorlófeladat
Egyszerre csak egyet csinálj: tervezd meg, írd meg, futtasd, ellenőrizd, és csak utána nyisd ki a megoldást.
1. Fizetésemelés mindenkinek
Egy Itt szándékosan nincs WHERE, mert mindenkit érint, ezért a megerősítés kötelező. Az egész számok osztása a tizedest levágja (nudSzazalek (1–50) mezőben megadott százalékkal emeld meg az összes dolgozó fizetését egy gombnyomásra. A művelet előtt kérj megerősítést, utána írd ki, hány dolgozót érintett.Egy lehetséges megoldás
SQLite: egész osztás), ezért a szorzást az osztás előtt végezzük. Az ExecuteNonQuery visszaadja az érintett sorok számát.// DB.cs
public static int FizetesEmeles(int szazalek)
{
using (SQLiteConnection kapcsolat = UjKapcsolat())
{
kapcsolat.Open();
using (SQLiteCommand parancs = new SQLiteCommand("UPDATE adatok SET fizetes = fizetes * (100 + @szazalek) / 100 WHERE fizetes IS NOT NULL", kapcsolat))
{
parancs.Parameters.AddWithValue("@szazalek", szazalek);
return parancs.ExecuteNonQuery();
}
}
}
// Form1.cs
private void btnEmeles_Click(object sender, EventArgs e)
{
int szazalek = (int)nudSzazalek.Value;
DialogResult valasz = MessageBox.Show($"Biztosan emeled mindenki fizetését {szazalek} %-kal?", "Fizetésemelés", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
if (valasz == DialogResult.Yes)
{
int db = DB.FizetesEmeles(szazalek);
Uzenet($"{db} dolgozó fizetése emelkedett.", false);
Frissit(kijeloltId);
}
}
2. Az összes törlése beírással
Egy Összes törlése gomb csak akkor töröljön mindent, ha a felhasználó egy felugró ablakban begépeli a TÖRLÉS szót. (Gondold végig: miért nehezebb véletlenül rákattintani, mint egy egyszerű Igen–Nem kérdésre?) A veszélyes, nem visszavonható műveleteknél a begépeléssel való megerősítés lassítja a felhasználót, és megakadályozza a véletlen kattintást. A beírás bekéréséhez a Windows Formsban nincs kész egyszerű ablak, ezért egy kis, külön Egy lehetséges megoldás
Form-ot használunk, vagy egyszerűbb megoldásként egy txtMegerosit mező és egy gomb teszi lehetővé a törlést, amíg a mezőben a TÖRLÉS szó áll.private void txtMegerosit_TextChanged(object sender, EventArgs e)
{
btnOsszesTorol.Enabled = txtMegerosit.Text == "TÖRLÉS";
}
private void btnOsszesTorol_Click(object sender, EventArgs e)
{
using (SQLiteConnection kapcsolat = DB.UjKapcsolat())
{
kapcsolat.Open();
using (SQLiteCommand parancs = new SQLiteCommand("DELETE FROM adatok", kapcsolat))
{
int db = parancs.ExecuteNonQuery();
Uzenet($"{db} dolgozó törölve.", false);
}
}
txtMegerosit.Clear();
Frissit(0);
Uj();
}
3. Dolgozó másolása
Egy Másolás gomb készítsen a kijelölt dolgozóról másolatot (új azonosítóval), és jelölje ki az új sort. Az Egy lehetséges megoldás
INSERT ... SELECT egy lekérdezés eredményét veszi fel új sorként. Az id oszlopot nem másoljuk, így az adatbázis új azonosítót ad.// DB.cs
public static long DolgozoMasolas(int id)
{
using (SQLiteConnection kapcsolat = UjKapcsolat())
{
kapcsolat.Open();
string sql = "INSERT INTO adatok (vnev, knev, fizetes, cim) SELECT vnev, knev, fizetes, cim FROM adatok WHERE id = @id";
using (SQLiteCommand parancs = new SQLiteCommand(sql, kapcsolat))
{
parancs.Parameters.AddWithValue("@id", id);
parancs.ExecuteNonQuery();
}
return kapcsolat.LastInsertRowId;
}
}
// Form1.cs
private void btnMasol_Click(object sender, EventArgs e)
{
if (kijeloltId == 0)
{
Uzenet("Előbb válassz ki egy dolgozót!", true);
return;
}
long ujId = DB.DolgozoMasolas(kijeloltId);
Frissit((int)ujId);
MezokTolt();
}
Gyakorlótár: 6 további feladat
Három szinten gyakorolhatsz: alap, közepes és kihívás. Az első négyet a DB Browser Execute SQL lapján oldd meg (előbb próbáld ki, utána vond vissza a Revert Changes gombbal, ha nem szeretnéd megtartani), az utolsó kettőhöz a dolgozó-nyilvántartó projektje kell. Csak a próbálkozás után nyisd le a megoldást.
Alap szint
1. Két új dolgozó
Vegyél fel két új dolgozót egyetlen futtatással, majd ellenőrizd a Az Execute SQL lapon több utasítást is futtathatsz, ha pontosvesszővel zárod őket. A végén a SELECT utasítással.Megoldás megnyitása
SELECT az eredményt mutatja.INSERT INTO adatok (vnev, knev, fizetes, cim) VALUES ('Orbán', 'Réka', 400000, 'Pécs');
INSERT INTO adatok (vnev, knev, fizetes, cim) VALUES ('Sipos', 'Tamás', 355000, 'Veszprém');
SELECT * FROM adatok ORDER BY id DESC LIMIT 2;
2. Egy sor javítása
Javítsd ki Kiss Márta (győri dolgozó) fizetését 395 000-re. Hogyan biztosítod, hogy csak őt érintse? Előbb keresd meg az azonosítóját egy Megoldás megnyitása
SELECT segítségével, majd az id alapján módosíts. A név alapján módosítani kockázatos, mert több azonos nevű dolgozó is lehet.SELECT id, vnev, knev FROM adatok WHERE vnev = 'Kiss' AND knev = 'Márta';
UPDATE adatok SET fizetes = 395000 WHERE id = 5; -- az előbb megtalált azonosító (nálad más is lehet)
Közepes szint
3. Fizetésemelés egy városban
A győri dolgozók fizetését emeld 5%-kal (egész forintra kerekítve). Előbb nézd meg, kiket érint. A Megoldás megnyitása
ROUND kerekít. A szorzás előtt kell a százalékot tizedes számmá alakítani (1.05), különben az egész osztás levágná az eredményt. Az előnézet ugyanazt a WHERE feltételt használja.SELECT vnev, knev, fizetes, ROUND(fizetes * 1.05) AS uj_fizetes
FROM adatok WHERE cim = 'Győr';
UPDATE adatok SET fizetes = ROUND(fizetes * 1.05) WHERE cim = 'Győr';
4. Biztonságos törlés
Töröld azokat a dolgozókat, akiknek nincs megadva a címük. Mutasd meg, hogyan győződsz meg előbb arról, hogy csak őket érinti. A hiányzó értéket az Megoldás megnyitása
IS NULL vizsgálja (nem az = NULL). Először a SELECT mutatja a törlendő sorokat, utána ugyanaz a feltétel a DELETE-ben.SELECT * FROM adatok WHERE cim IS NULL;
DELETE FROM adatok WHERE cim IS NULL;
Kihívás szint
5. Hányat érintett a művelet?
A mentés és a törlés után a A lblUzenet írja ki, hány sort érintett a művelet (például 1 sor módosult). Mit tegyél, ha az ExecuteNonQuery 0-t ad?Megoldás megnyitása
DB metódus int értéket ad vissza az érintett sorok számáról, és az ablak ez alapján írja ki az üzenetet. Nulla találat esetén figyelmeztetés kell, mert nem történt módosítás.// DB.cs: a DolgozoModositas visszatérési típusa int lesz
public static int DolgozoModositas(int id, string vnev, string knev, int fizetes, string cim)
{
// ... ugyanaz ...
return parancs.ExecuteNonQuery();
}
// Form1.cs
int erintett = DB.DolgozoModositas(kijeloltId, vnev, knev, fizetes, cim);
if (erintett == 0)
{
Uzenet("Nem történt módosítás: a dolgozó nem található.", true);
}
else
{
Uzenet($"{erintett} sor módosult.", false);
}
6. Az utolsó törlés visszavonása
Törlés után egy Visszavonás gomb vegye fel újra a legutóbb törölt dolgozót (új azonosítóval). A törölt adatokat a program tárolja a törlés előtt. A törlés előtt elmentjük a mezők tartalmát négy mezőben. A visszavonás ezekből egy új Megoldás megnyitása
INSERT-et futtat. Ez nem az eredeti sor visszaállítása (az azonosító új lesz), csak az adatok helyreállítása. A gomb csak akkor aktív, ha van mit visszavonni.private string toroltVnev = "";
private string toroltKnev = "";
private string toroltCim = "";
private int toroltFizetes = 0;
// a törlés előtt (a megerősítés után):
toroltVnev = txtVnev.Text;
toroltKnev = txtKnev.Text;
toroltCim = txtCim.Text;
toroltFizetes = (int)nudFizetes.Value;
btnVisszavon.Enabled = true;
private void btnVisszavon_Click(object sender, EventArgs e)
{
long ujId = DB.DolgozoFelvetel(toroltVnev, toroltKnev, toroltFizetes, toroltCim);
Frissit((int)ujId);
MezokTolt();
btnVisszavon.Enabled = false;
Uzenet("A törölt dolgozó visszaállítva.", false);
}
Gyors önellenőrzés
Válaszolj fejben, és csak utána nyisd le a választ. Az utasítás a tábla összes sorát érinti: mindenkit módosít, illetve kiüríti a táblát. Mert az elsődleges kulcs minden sort egyedileg azonosít. A név vagy a sorszám nem megbízható. Az érintett sorok számát. Nulla azt jelenti, hogy a feltételnek nem felelt meg egyetlen sor sem. A Az üres szöveg egy érték (nulla karakter), a Eldobja az utolsó Mert a törlés nem vonható vissza, és a véletlen kattintás adatvesztést okozna.1. Mi történik, ha az UPDATE vagy a DELETE végéről kimarad a WHERE?
2. Miért az id alapján módosítunk és törlünk?
3. Mit ad vissza az ExecuteNonQuery?
4. Hogyan szerzed meg az újonnan felvett sor azonosítóját?
kapcsolat.LastInsertRowId tulajdonságból (long típus).5. Mi a különbség az üres szöveg és a NULL között?
NULL hiányzó, ismeretlen érték. A C# kódban a DBNull.Value felel meg neki, az SQL-ben az IS NULL vizsgálja.6. Mire való a Revert Changes a DB Browserben?
Write Changes óta történt összes módosítást, így egy elrontott UPDATE vagy DELETE kipróbálás után visszaállítható az adatbázis.7. Miért kell megerősítés törlés előtt?
Mit tudsz már?
- Az
INSERT,UPDATEésDELETEutasítástWHERE id = ...feltétellel használod. - Az érintett sorok számából ellenőrzöd a művelet sikerét.
- Az új sor azonosítóját a
LastInsertRowIdadja. - A hiányzó értéket
DBNull.Valuealakban kezeled. - Táblázat-kijelölést és szerkesztőmezőket kötsz össze, a törlést megerősítéssel védi.
Következő lecke: paraméterek és SQL-biztonság
A módosító utasítások kész. A következő leckében a paraméterezett lekérdezéseket mélyítjük: több paraméter, dátumok, NULL és a leggyakoribb biztonsági hibák.




