Anda di halaman 1dari 68

Gregorics Tibor

Az ADO.NET osztlyai

ADO.NET osztlyai
ADO.NET OSZTLYAI ........................................................................................................... 1
0. ESZKZK....................................................................................................................................................... 2

Adatbzis szerver................................................................................................................ 2 ADO.NET osztlyai ............................................................................................................ 2 Server Explorer .................................................................................................................. 2 SQL Server Managment Studio Express ............................................................................ 3
1. SZMLLS EGY ADATTBLBAN .................................................................................................................. 4 2. ADATTBLA MDOSTSA .............................................................................................................................. 7 3. ADATTBLA ADATAINAK MEGJELENTSE ...................................................................................................... 8 4. TBB LPSES ADATBZIS MVELETEK ........................................................................................................ 11 5. ADATTBLA-KARBANTARTS A MEMRIBAN ............................................................................................. 12

Els megolds (elemi eszkzkkel) .................................................................................. 12 Msodik megolds (adapterrel) ....................................................................................... 21 Harmadik megolds (varzslval) ................................................................................... 24 A .NET Framework az adatbzisok kezelst az ADO.NET-ben definilt osztlyokkal tmogatja. Ennek a fejezetnek az a clja, hogy kismret alkalmazsok bemutatsn keresztl zeltt adjon ezen osztlyok hasznlatrl.1 Nem treksznk ezen osztlyok minden rszletre kiterjed ismertetsvel ezt mind nyomtatott, mind online szakirodalmakban megtallhatjuk , helyette az alkalmazsaikra helyezzk a hangslyt. Az albbiakban olyan konzolalkalmazsokat mutatunk, amelyekben klnfle SQL parancsokkal, trolt eljrsokkal s tranzakcikkal kezelnk egy adatbzist. A feladatokat egy kpzelt utazsi iroda apartman-foglalsi tevkenysghez hasznlt Apartments adatbzisra fogalmazzuk meg. Ebben a fejezetben ennek az adatbzisnak kizrlag az pletek lersra szolgl building nev tblja szerepel.
CREATE TABLE building ( building_id INTEGER PRIMARY KEY, name VARCHAR(30), city_id INTEGER NOT NULL, street VARCHAR(30) NOT NULL, sea_distance INTEGER, shore_id INTEGER, features INTEGER, comment VARCHAR(100), FOREIGN KEY (city_id) REFERENCES city, FOREIGN KEY (shore_id) REFERENCES shore );

A feladatok kitzse s megoldsa eltt nhny sz az alkalmazsokban hasznlt eszkzkrl.

Az osztlyok bemutatsnl Jason Price C# adatbzisprogramozs c. knyvre (2004, KisKapu Kft.) tmaszkodtam

Gregorics Tibor

Az ADO.NET osztlyai

0. ESZKZK Adatbzis szerver Az adatbzisok kezelshez (ltrehozshoz, trolshoz, tulajdonsgainak belltshoz, adatainak felvitelhez, trlshez, mdostshoz) valamilyen adatbzis szerverre van szksgnk. A .NET sokfle adatbzis szerver hasznlatt tmogatja, de ezek kztt prioritst lvez a Microsoft sajt termke: az MS SQL SERVER. A .NET felteleptsvel egytt hozzjuthatunk ennek egyszerbb vltozathoz az MS SQL SERVER EXPRESS-hez. A tovbbiakban bemutatott plda-alkalmazsokban ezt hasznljuk.2 ADO.NET osztlyai Az ADO.NET azoknak az osztlyoknak a gyjtemnye, amelyek az adatkezelst tmogatjk. Ezen bell beszlhetnk az gynevezett adatszolgltat osztlyokrl, amelyek az adatbzis s a kliens program kztti adatforgalom megvalstshoz nyjtanak segtsget, valamint az gynevezett adattrolsi osztlyokrl, amelyek az adatbzisbl letlttt adatok trolsra, manipullsra adnak lehetsget. Az adatszolgltat osztlyokat aszerint csoportostjuk, hogy milyen tpus kommunikcit tmogatnak adatbzis szerverrel. A klnbz csoportok osztlyai ms-ms nvtrben tallhatak, s az osztlyok nevnek eltagja (prefixe) is eltr. Ugyanakkor a klnbz eltag, de klnben azonos nev osztlyok funkcionalitsa megegyezik. SQL Server - SQL Server 7.0 -tl; ilyen pldul az MS SQL Express - System.Data.SqlClient nvtrben "Sql"-lel kezdd osztlynevek OLE DB (Object Linking and Embedding for Databases) - OLE DB-t tmogat adatszerverek; ilyenek SQL Server 7.0 alatti verzii - System.Data.OleDb nvtrben "OleDb"-vel kezdd osztlynevek ODBC (Open Database Connectivity) - ODBC-t tmogat adatbzisszerverek, ilyen pldul az Access, a MySQL - System.Data.Odbc nvtrben "Odbc"-vel kezdd osztlynevek Oracle - Oracle (8.1.7.-tl) tmogat adatbzisszerverek - System.Data.OracleClient nvtrben "OracleClient"-vel kezdd osztlynevek Server Explorer Ha elindtjuk a .NET Visual Studio-jt, akkor a Server Explorer nzetben tudunk j adatbzist ltrehozni, tblkat, trolt eljrsokat definilni, tblkat feltlteni, meglv adatbzisokat megtekinteni, mdostani, kiegszteni. Elfordul, hogy a Visual Studio elindtst megelzen ms eszkzzel (lsd kvetkez pont) hoztunk ltre egy j adatbzist, akkor az a Server Explorerben mg nem ltszik. Ekkor a DataConnections felett jobb egrfl kattintsra felnyl menben az Add Connection pontot kell kivlasztani, majd az erre megnyl panelen a kvnt adatbzist beazonostani.

Ebben s a ksbbi fejezetekben a .NET 2005-s vltozatval teszteltem a mintaprogramokat.

Gregorics Tibor

Az ADO.NET osztlyai

SQL Server Managment Studio Express Az SQL Server Managment Studio Express egy ingyenes szoftver, mellyel Visual Studio nlkl tudjuk az MS SQL SERVER-t kezelni. Segtsgvel j adatbzist hozhatunk ltre, bellthatjuk annak tulajdonsgait, feltlthetjk adatokkal az adattblit, SQL parancsokat, trolt eljrsokat, tranzakcikat prblhatunk ki. Gyakran elfordul feladat, hogy egy adatbzist kt munkahely MS SQL szervere kztt kell hordozni. Ilyenkor pldul a dump database <adatbzisnv> to disk='fjlnv.dat' parancs segtsgvel menthetjk el az adatbzist. Ez a fjl a Microsoft SQL Server\Mssql.1\Mssql\Backup mappba kerl. A fjlt tszlltva a msik szerver ugyanilyen nev mappajba a load database <adatbzisnv> from disk='fjlnv.dat' paranccsal tudjuk az adatbzist birtokba venni.

Gregorics Tibor

Az ADO.NET osztlyai

1. Szmlls egy adattblban Feladat: A building tbla hny plete (sora) tallhat a via Fausta utcban? A megoldshoz kt specilis objektumra lesz szksgnk. Az adatbzishoz egy Connection tpus objektum (legyen a neve: con) segtsgvel tudunk kapcsoldni. A kapcsolat kiptshez meg kell adnunk az gynevezett kapcsolati sztringet, amely tartalmazza az adatbzis nevt, az adatbzis szervert, a kapcsolat biztonsgi szintjt. A con.Open() metdus kapcsolatot pt az adatbzissal, amit a con.Close() metdus bont szt. Amg a kapcsolat fenn ll, csak mi hasznlhatjuk az adatbzist.

Connection
Tulajdonsg
ConnectionString State

Tpus
string ConnectionState

Magyarzat A kapcsolati sztringet trolja A kapcsolat sttusza lehet: Open, Connecting,Executing,Fetching, Broken,Closed Magyarzat Megnyitja a kapcsolatot Lezrja a kapcsolatot Ltrehozza a kapcsolat egy parancsobjektumt

Metdus
Open() Close() CreateCommand()

Visszatrsi tpus
void void SqlCommand

A kapcsolati objektum ltrehozsnak egy mdja:


SqlConnection con = new SqlConnection ( @"database=Apartments; server=computer\sqlexpress" + "Persist Security Info=False; Integrated Security=SSPI;" );

A kapcsolati sztring megadsnak van ennl elegnsabb mdja is. Ilyenkor a kapcsolati sztringet nem kzvetlenl a programkdba rjuk be, hanem egy gynevezett konfigurcis fjlba. Ebben a fjlban XML formban szerepelhetnek olyan adatok, amelyeket a programunk hasznl, s amelyek megvltoztatsakor nem kell a programot jrafordtani. Ez akkor elnys, amikor az adatbzis-kezel alkalmazsunkat klnbz krnyezetekbe teleptjk, ahol msms kapcsolati sztringgel kell dolgoznunk. Adjunk hozz a projektnkhz egy konfigurcis fjlt! Ehhez: 1. Kattintsunk a Solution Explorer-ben a projekt neve felett a jobb egrgombbal. 2. Vlasszuk ki a felnyl menbl az Add / New Item pontokat, majd a megjelen ablakban az Application Configuration File smt, s fogadjuk el a felajnlott fjlnevet (App.config). 3. rjuk bele az gy ltrehozott konfigurcis fjlba az albbi XML kdot! Ebben egyetlen egysget, egy ConnectionString-et definilunk, amelynek van neve (Apartments) s tartalma (ez a kapcsolati sztring).

Gregorics Tibor

Az ADO.NET osztlyai

<?xml version="1.0" encoding="utf-8" ?> <configuration> <connectionStrings> <add name = "Apartments" connectionString = "server=computer\sqlexpress; database=Apartments; Integrated Security=SSPI; Persist Security Info=False;" /> </connectionStrings> </configuration>

A kapcsolati objektum ltrehozsnl az App.config llomnyban Apartments nven azonostott kapcsolati sztringet hasznljuk. Ehhez a sztringhez a programban gy frhetnk hozz, hogy pldnyostunk egy kapcsolatsztring-bellt objektumot a ConfigurationManager osztly ConnectionStrings (statikus) tulajdonsgnak segtsgvel. Ennek t adjuk a konfigurcis llomnyban a kapcsolati sztringet azonost Apartments nevet. Ezutn a kapcsolatsztring-bellt objektum ConnectionString tulajdonsga tartalmazza a kapcsolati sztringet.
ConnectionStringSettings settings =ConfigurationManager. ConnectionStrings["Apartments"]; if (settings == null) return; SqlConnection con = new SqlConnection(settings.ConnectionString);

A kd lefordtshoz szksg van a program elejn a using System.Configuration sorra. Ezt a knyvtrat hozz kell venni a projektnk referenciihoz: 1. Kattintsunk a Solution Explorer-ben a projekt neve felett a jobb egrgombbal. 2. Vlasszuk ki az Add Reference pontot, majd a megjelen ablak Recent fln a System Configuration komponenst. A feladat megoldshoz szksges SQL lekrdezst (SELECT COUNT(*) FROM building WHERE street = via Fausta) egy Command (parancs) objektum (legyen a neve: cmd) segtsgvel kldhetjk el az adatbzisnak. A parancs objektumnak ismernie kell azt a kapcsolati objektumot (con), amely azonostja szmra a lekrdezs adatbzist. Ez a cmd.Connection = con rtkadssal llthat be, vagy gy, ha a cmd objektumot a con.CreateCommand() metdussal hozzuk ltre. A lekrdezs elkldse eltt meg kell nyitnunk az adatbzis irnyban a kapcsolatot. A lekrdezs elkldsnek mdja a vgrehajtand SQL parancs fajtjtl fgg. Ha az SQL parancs mint ebben ez esetben is vlaszknt egyetlen rtket vr, akkor a cmd parancsot annak ExecuteScalar() metdusval kell elkldeni az adatbzisszervernek. Ez a metdus visszatrsi rtkben adja vissza a lekrdezs eredmnyt. Az eredmny object tpus, amit a kvnt tpusra tudunk konvertlni.

Gregorics Tibor

Az ADO.NET osztlyai

Command
Tulajdonsg
CommandText CommandType

Tpus
string CommandType

Magyarzat SQL parancs szvege vagy a kiolvasand tbla neve vagy a vgrehajtand trolt eljrs neve A CommandText-ben trolt szveg fajtja
(Text,TableDirect,StoredProcedure) alaprtelmezett rtke a Text.

Connection Parameters

SqlConnection SqlParameters Collection

A parancshoz tartoz kapcsolati objektum Itt adhatak meg a parancs paramtereinek konkrt rtkei a parancs vgrehajtsa eltt. Magyarzat Megnyitja a kapcsolatot Lezrja a kapcsolatot Ltrehozza a kapcsolat egy parancsobjektumt

Metdus
ExecuteScalar() ExecuteNonQuery() ExecuteReader()

Visszatrsi tpus
object int SqlReader

using System; using System.Configuration; using System.Data; using System.Data.SqlClient; ... ConnectionStringSettings settings =ConfigurationManager. ConnectionStrings["Apartments"]; if (settings == null) return; SqlConnection con = new SqlConnection(settings.ConnectionString); SqlCommand cmd = con.CreateCommand(); cmd.CommandText = "SELECT COUNT(*) FROM building" + "WHERE street = via Fausta ;"; try { con.Open(); int count = (int)cmd.ExecuteScalar(); Console.WriteLine("Ekordok szma: {0}", count); } catch (SqlException ex) { Console.WriteLine("Hiba: {0}", ex.Message); } finally { con.Close(); Console.ReadLine(); }

A kapcsolat ltrehozsa, illetve az SQL parancs vgrehajtsa sorn fellp hibk SqlException kivtelt dobhatnak, amelyeket kezelni kell.

Gregorics Tibor

Az ADO.NET osztlyai

2. Adattbla mdostsa Feladat: Szrjuk be egy j plet adatait, trljk a 2-es azonostj pletet, s vltoztassuk a 12-es azonostj plet tengertl mrt tvolsgt 50-re! A megoldshoz szksg van egy kapcsolat (SqlCommand con) s hrom parancs (SqlCommand insertcmd, deletecmd, updatecmd) objektumra. Amikor az SQL parancs megvltoztatja az adatbzist (INSERT, DELETE, UPDATE, DROP, ALTER, stb.), a parancsot az ExecuteNonQuery() metdussal kell elkldeni az adatbzis szervernek. Az ExecuteNonQuery() metdus visszaadja a parancs ltl tnylegesen megvltoztatott sorok szmt. Ezt hiba-ellenrzsre tudjuk felhasznlni. Termszetesen itt is figyelni kell az SqlException-t, hiszen sokfle hiba (SQL parancs szintaxisa, elsdleges kulcs nem egyedi volta, nem megengedett null rtk, nem ltez kulcs, stb.) fellphet az albbi kdrszletben.
... SqlCommand insertcmd = con.CreateCommand(); insertcmd.CommandText = "INSERT INTO building (building_id," + "name,city_id,street,sea_distance,shore_id,features,comment)" + "VALUES ('23','Villa','1','via Europa','100','2','5','etc');"; SqlCommand deletecmd = con.CreateCommand(); deletecmd.CommandText = "DELETE FROM building" + "WHERE building_id = '2';"; SqlCommand updatecmd = con.CreateCommand(); updatecmd.CommandText = "UPDATE building " + "SET sea_distance = '50' WHERE building_id = '12';"; int ni, nd, nu; ni = nd = nu = 0; try { con.Open(); ni = insertcmd.ExecuteNonQuery(); nd = deletecmd.ExecuteNonQuery(); nu = updatecmd.ExecuteNonQuery(); } catch (SqlException ex) { Console.WriteLine("Hiba: {0}", ex.Message); } finally { con.Close(); Console.WriteLine("beszrt sorok: {0}", ni); Console.WriteLine("trlt sorok: {0}", nd); Console.WriteLine("mdostott sorok: {0}", nu); Console.ReadLine(); } ...

Gregorics Tibor

Az ADO.NET osztlyai

3. Adattbla adatainak megjelentse Feladat: rjuk ki konzol ablakba a building tbla sszes sora name, street s sea_distance mezinek rtkt! A megoldshoz a mr megismert kapcsolat (SqlCommand con) s parancs (SqlCommand cmd) objektumok mellett egy harmadik fajta objektum is kell. A cmd objektum most a "SELECT name, street, sea_distance FROM building" SQL parancsot tartalmazza, mellyel a building tbla sszes sort le tudjuk krni az adatbzistl. Azt az SQL parancsot, amely sorokat kr le, az ExecuteReader() metdussal hajtjuk vgre. Ez a metdus egy DataReader tpus, gynevezett adatolvas objektumot (legyen a neve: reader) ad vissza, amellyel hozzfrhetnk a lekrdezs eredmnyhez. A reader.Read() metdussal rllhatunk a lekrdezett sorok kzl a soron kvetkezre (kezdetben az elsre). A reader.Read()false rtke jelzi, hogy mr nincs kvetkez sor. Ha van, akkor a reader egy sorra (az aktulisra) hivatkozik, amelynek oszlopait pldul a reader[oszlopnv] formban tudjuk elrni.

SqlDataReader
Tulajdonsg
FieldCount

Tpus
int

Magyarzat Az adott sor oszlopainak szma Magyarzat A kvetkez sorra lp, ha nincs, akkor false Visszaadja, van-e kvetkez sor. Aktulis sor adott sorszm oszlopnak nevt adja meg Aktulis sor adott nev oszlopnak sorszmt adja meg Aktulis sor adott sorszm vagy nev oszlopnak rtkt adja meg Aktulis sor oszlopainak rtkt az adott objektumtmbbe msolja s visszaadja a tmb elemeinek szmt Vizsglja, hogy az aktulis sor adott sorszm oszlopa null rtket tartalmaz-e Aktulis sor adott sorszm oszlopnak rtkt a megfelel tpusra konvertlva adja meg

Metdus
Read() NextResult() GetName(sorszm) GetOrdinal("oszlopnv") [sorszm] ["oszlopnv"] GetValues(tmb)

Visszatrsi tpus
bool bool string int object int

IsDBNull(sorszm) Get*(sorszm) GetValue(sorszm) GetBoolean(sorszm) GetInt16(sorszm)

bool

object bool short

Az SQL szerver adattpusai (az oszloptpusok) nem azonosak a programozsi nyelvek tpusaival, de a C# nyelven minden oszloptpushoz megtallhat az annak megfelel tpus, s az arra konvertl fggvny (lsd Get* metdusokat). Ezek mellett a .NET definilja az SQL szerveren rvnyes gynevezett Sql* tpusokat (SqlBoolean, SqlByte, SqlDouble, 8

Gregorics Tibor

Az ADO.NET osztlyai

SqlInt16, SqlString stb.) is, amelyekre GetSql* (GetSqlBoolean, GetSqlByte, GetSqlDouble, GetSqlInt16, GetSqlString stb.) metdusokkal lehet konvertlni.

A reader["oszlopnv"] rtkt is ltalban konvertlni kell, de az albbi kdban konverzira nem lesz szksg, hiszen a Console.Write() az object tpus rtkeket gyis sztringg alaktja. A megold kdnak most csak a lnyeges, a korbbi kdtl eltr rszlett mutatjuk meg.

SqlCommand cmd = con.CreateCommand(); cmd.CommandText = "SELECT * FROM building"; SqlDataReader reader = null; try { con.Open(); reader = cmd.ExecuteReader(); while (reader.Read()) { Console.Write("name = "); Console.WriteLine(reader["name"]); Console.Write("street = "); Console.WriteLine(reader["street"]); Console.Write("sea_distance = "); Console.WriteLine(reader["sea_distance"]); Console.WriteLine(); } } catch (SqlException ex) { Console.WriteLine("Hiba: {0}", ex.Message); Console.ReadLine(); return; } finally { if(reader != null) reader.Close(); if(con != null) con.Close(); Console.ReadLine(); }

Gregorics Tibor

Az ADO.NET osztlyai

Feladat: Hny plet (sor) van a building tblban, s mennyi a legkzelebbi tengertl mrt tvolsg? A szmtott rtk lekrdezst a sorok lekrdezshez hasonlan e az ExecuteReader() metdussal vgezzk.
... SqlCommand cmd = con.CreateCommand(); cmd.CommandText = "SELECT COUNT(*), MIN(sea_distance)" + "FROM building;"; con.Open(); object[] results = new object[2]; SqlDataReader reader = cmd.ExecuteReader(); reader.Read(); reader.GetValues(results); Console.WriteLine("sszes={0}", (int)results[0]); Console.WriteLine("Minimlis={0}", (int)results[1]); reader.Close(); con.Close(); ...

10

Gregorics Tibor

Az ADO.NET osztlyai

4. Tbb lpses adatbzis mveletek Az sszetett SQL parancsokat ltalban a szerver oldalon megrt trolt eljrsok tartalmazzk. A DeleteBuilding nev trolt eljrs egy pletet trl, de eltte kitrli az sszes olyan apartmant az apartment tblbl, amelyek a trlni kvnt pletben tallhatk:
CREATE PROCEDURE dbo.DeleteBuilding ( @id int ) AS BEGIN DELETE apartment WHERE building_id = @id; DELETE building WHERE building_id = @id; RETURN END

Az albbi kdrszlet a DeleteBuilding trolt eljrst hvja meg. A cmd objektum most nem CommandType.Text formj, hanem CommandType.StoredProcedure. Ez jelzi, hogy a CommandText egy trolt eljrs nevt tartalmazza. A parancs vgrehajtsa eltt rtket kell tadnunk a trolt eljrs paramternek.
SqlCommand cmd = con.CreateCommand(); cmd.CommandType = CommandType.StoredProcedure; cmd.CommandText = "DeleteBuilding"; cmd.Parameters.Add("@id", SqlDbType.Int).Value = 12; cmd.ExecuteNonQuery();

Ha a kliens oldalon ksztjk el a tbb lpsbl ll adatbzis kezelsnket, akkor azt rdemes tranzakciba fzni. Az albbi kdrszlet kzppontjban egy Transaction objektum (neve: trans) ll. Az egyazon tranzakciban vgrehajtand parancsokat ehhez kell hozzrendelni. A parancsok vgrehajtsa utn lehetsgnk van vglegesteni (trans.Commit(), vagy visszavonni (trans.RollBack()) azokat.
SqlTransaction trans = con.BeginTransaction( Data.IsolationLevel.Serializable); SqlCommand cmd1 = con.CreateCommand(); cmd1.Transaction = trans; ... int n1 = cmd1.ExecuteNonQuery(); SqlCommand cmd2 = con.CreateCommand(); cmd2.Transaction = trans; ... int n2 = cmd2.ExecuteNonQuery(); if(...) trans.Commit(); else trans.Rollback();

11

Gregorics Tibor

Az ADO.NET osztlyai

5. Adattbla-karbantarts a memriban Feladat: Olvassuk be az Apartments adatbzis building nev tbljt, vltoztassuk meg nhny adatt, majd mentsk vissza az adatbzisba! Hromfle megoldst fogunk mutatni, amelyek nem az eredmnykben, de mg csak nem is kdjukban, hanem a kdjukat elllt technikkban trnek el. Mindegyik megolds futs kzben egy olyan adattbla (DataTable) objektumot hoz majd ltre, amelyben (a memriban) az adatbzis building tbljt a letlts utn el tudjuk helyezni. Az adattbla objektumot begyazzuk egy msik, gynevezett adathalmaz (DataSet) objektumba, amely kpes tbb tblt s az azok kztti kapcsolatokat is trolni. Elszr egy olyan konzol-alkalmazst ltunk, amelyben ez eddig bemutatott elemi eszkzk (Connection, Command) segtsgvel olvassuk be a teljes adattblt az adatbzisbl egy adathalmazba (pontosabban annak adattbla objektumba), majd az gy letlttt adatok megvltoztatsa (trls, beszrs, mdosts) utn visszamentjk a vltoztatsokat az adatbzisba. Ezt kveten gy mdostjuk ezt a megoldst, hogy a letlts s visszaments fzisok a megrt kd szintjn egyszersdjenek. Ehhez egy gynevezett adapter objektumot fogunk hasznlni, mert ez rendelkezik a letltst s a visszamentst vgz metdusokkal, amelyek meghvsval az els megoldsban alkalmazott ciklusokat helyettesthetjk. Harmadik lpsben megnzzk, hogyan lehet a Visual Studio varzsljval olyan osztlyokat generlni, amelyek pldnyostsval elllthatjuk az adathalmazt s az adaptert. Els megolds (elemi eszkzkkel) Az els megolds az albbi rszekbl ll: 1. Egy adathalmazbeli adattbla objektum ltrehozsa a building tbla adatai szmra. 2. Kapcsolati objektum s a building tbla adatainak letltshez szksges parancs objektum ltrehozsa. 3. A building tbla letltse az adatbzisbl az adattbla objektumba. 4. Az adattbla objektum adatainak vltoztatsa. 5. Parancs objektumok definilsa a mentshez. 6. Ments az adattbla objektumbl az adatbzis building tbljba. Adathalmaz s adattbla objektumok ltrehozsa A jelen feladatunk megoldshoz tulajdonkppen elegend lenne egy nll adattbla objektum. A ksbbi feladatok elksztse, az ltalnosts lehetsge miatt mr most belegyazzuk ezt egy adathalmaz objektumba. Egy adathalmaz (DataSet) szlssges esetben akr a teljes adatbzist trolhatja a memriban, ltalban azonban az adatbzisnak csak egy rszt, egy-kt tbljt (sokszor azokat is megszrve) troljuk benne. Az adathalmaz lnyegben kt gyjtemnybl ll. A Tables adattbla objektumokat (DataTable), a Relations pedig az adattblk kztti (pl. idegen-kulcs) kapcsolatokat ler objektumokat (DataRelation) trolja. Az adathalmaz objektum szmos metdussal rendelkezik. Az albbi tblzat csak nhnyat emlt ezek kzl. rdekes felfigyelni az adathalmaz azon jellemzjre, hogy adatvltozs esetn emlkszik az adatok eredeti rtkre is, amelyek ha szksges visszallthatk 12

Gregorics Tibor

Az ADO.NET osztlyai

(RejectChanges()). Tovbbi rdekessg, hogy az adathalmazbeli adatoknak meg kell felelnik azon megszortsoknak, feltteleknek, amelyeket egy adatbzisban is meg szoktunk adni, feltve, hogy ezek ellenrzst nem kapcsoljuk ki (EnforceConstraints). A hibs adatokra a HasErrors tulajdonsg utal.

DataSet
Tulajdonsg
Tables Relations DataSetName HasErrors EnforceConstraints

Tpus
DataTableCollections DataRelationCollections string bool bool

Magyarzat Adattblk gyjtemnye Adattblk gyjtemnye Objektum neve Jelzi, hogy vannak hibkat tartalmaz sorok a tblkban Bellthat illetve lekrdezhet, hogy frisstskor figyelembe kell-e venni a megszortsokat. Magyarzat Vglegess teszi az utols feltlts vagy az AcceptChanges() legutbbi meghvsa utn keletkezett vltozsokat. Visszavonja az utols feltlts vagy az AcceptChanges() legutbbi meghvsa utn keletkezett vltozsokat. Lemsolja s visszaadja az utols feltlts vagy az AcceptChanges() legutbbi meghvsa utn keletkezett vltozsokat. Trli az sszes tbla sszes sort kztti kapcsolatok

Metdus
AcceptChanges()

Visszatrsi tpus
void

RejectChanges()

void

GetChanges()

DataSet

Clear()

void

Az adattbla (DataTable) objekum tartalmaz minden olyan informcit, amely egy adattbla esetben lnyeges: az oszlopokat, illetve azok tulajdonsgait ler (DataColumn) objektumok gyjtemnyt; a sorokat megad (DataRow) objektumok gyjtemnyt; az elsdleges kulcshoz tartoz oszlopokat; a tblban lev idegenkulcs kapcsolatokat s a kulcsokra (elsdleges s idegen) vonatkoz megszortsokat. Tovbbi tulajdonsg az adattbla neve, valamint hivatkozs a tblt tartalmaz adathalmazra. Az albbi tblzatban felsorolt nhny metdus kzl most mg egyet sem fogunk hasznlni, hiszen az elsdleges kulcs megadsn kvl csak az oszlopok gyjtemnyvel dolgozunk: teht oszlopokat kell definilnunk. Ksbb azonban szksg lesz ezekre a metdusokra, pldul j sor ltrehozsakor.

13

Gregorics Tibor

Az ADO.NET osztlyai

DataTable
Tulajdonsg
Columns Rows PrimaryKey Constraints ChildRelations Tablename DataSet

Tpus
DataColumnCollection DataRowCollection DataColumn[] ConstraintCollection DataRelationCollection string DataSet

Magyarzat Oszlopok gyjtemnye Sorok gyjtemnye Elsdleges kulcs oszlopai Megszortsok gyjtemnye Kapcsolatok gyjtemnye Tblanv Hivatkozs a begyaz DataSet objetumra Magyarzat Trli az sszes sort Lemsolja az utols feltlts vagy az AcceptChanges() legutbbi meghvsa utn keletkezett vltozsokat. Visszaadja az sszes hibs sort j sort hoz ltre a DataTable tulajdonsgaival Keres vagy frisst vagy ltrehoz egy megadott sort Vglegess teszi az utols feltlts vagy az AcceptChanges() legutbbi meghvsa utn keletkezett vltozsokat. Visszavonja az utols feltlts vagy az AcceptChanges() legutbbi meghvsa utn keletkezett vltozsokat. Megadott feltteleknek eleget tev sorainak tmbjt adja vissza

Metdus
Clear() GetChanges()

Visszatrsi tpus
void DataTable

GetErrors() NewRow() LoadDataRow AcceptChanges()

DataRow[] DataRow DataRow void

RejectChanges()

void

Select()

DataRow[]

A kvetkez kdrszletben ltrehozunk egy adattblt egy adathalmazban, majd definiljuk a tblnak az oszlopait. Ez utbbit tbbflekppen is megtehetjk. Mi egy olyan Add() metdust hasznlunk, amelyik ltrehoz egy oszlopot, ehhez az oszlop nevt s tpust kell megadni, s azt hozzveszi a tblhoz. Ezutn az oszlop nevvel tudunk hivatkozni az adattbla objektum Columns gyjtemnynek adott oszlopra. Ezt hasznljuk ki, amikor a name oszlopnl belltjuk azt a megszortst, hogy adatbzis-null rtket is tartalmazhat. Vgl megadjuk az adattbla elsdleges kulcst a hozztartoz oszlopok felsorolsval. Az adattbla objektum oszlopaira minden olyan megszortst bellthatnnk, amely az objektumot az adatbzis building tbljhoz hasonlv tenn. Most azonban szndkosan nem definilunk minden megszortst azrt, hogy illusztrlhassuk azt az esetet, amikor az adattbla objektum nmagban ugyan helyes adatokat trol, de ezek visszamentse az adatbzisba hibt okoz.

14

Gregorics Tibor

Az ADO.NET osztlyai

DataSet ds = new DataSet("buildings"); DataTable dt = new DataTable("building"); ds.Tables.Add(dt); dt.Columns.Add("building_id", typeof(int)); dt.Columns.Add("name", typeof(string)); dt.Columns.Add("city_id", typeof(int)); dt.Columns.Add("street", typeof(string)); dt.Columns.Add("sea_distance", typeof(int)); dt.Columns.Add("shore_id", typeof(int)); dt.Columns.Add("features", typeof(int)); dt.Columns.Add("comment", typeof(string)); dt.Columns["name"].AllowDBNull = true; dt.PrimaryKey = new DataColumn[] { dt.Columns["building_id"] };

Az adattbla objektum oszlopainak legfontosabb jellemzi:

DataColumn
Tulajdonsg
ColumnName Ordinal DataType DefaultValue AutoIncrement AutoIncrementSeed AutoIncrementStep Caption Unique AllowDBNull Readonly Table

Tpus
string int Type object bool long long string bool bool bool DataTable

Magyarzat Oszlop neve Oszlop sorszma Oszlop tpusa Alaprtelmezett rtk Bellthat, hogy az oszlop rtke automatikusan szmtdjon-e Automatikus rtk generls esetn az indul rtk Automatikus rtk generls nvekmnye Oszlop cmsora Bellthat, hogy az oszlop rtke egyedi-e Bellthat, hogy az oszlop elfogad-e null rtket Bellthat, hogy az oszlop csak olvashat-e Hivatkozs a begyaz DataTable objetumra

15

Gregorics Tibor

Az ADO.NET osztlyai

Kapcsolati objektum s a letlts parancs objektumnak ltrehozsa


ConnectionStringSettings settings = ConfigurationManager.ConnectionStrings["Apartments"]; if (settings == null) return; SqlConnection con = new SqlConnection(settings.ConnectionString); SqlCommand cmd = con.CreateCommand(); cmd.CommandText = "SELECT * FROM building";

A building tbla letltse az adattbla objektumba


SqlDataReader reader = null; try{ con.Open(); reader = cmd.ExecuteReader(); while (reader.Read()){ DataRow row = dt.NewRow(); row["building_id"] = reader["building_id"]; row["name"] = reader["name"]; row["city_id"] = reader["city_id"]; row["street"] = reader["street"]; row["sea_distance"] = reader["sea_distance"]; row["shore_id"] = reader["shore_id"]; row["features"] = reader["features"]; row["comment"] = reader["comment"]; dt.Rows.Add(row); } dt.AcceptChanges(); } catch (SqlException ex){ Console.WriteLine("Adatbzis hiba: {0}", ex.Message); Console.ReadLine(); return; } finally { if(reader != null) reader.Close(); if(con != null) con.Close(); Console.ReadLine(); }

Ez a fzis nagyon hasonlt arra, amikor egy tbla tartalmt kilistztuk a konzolablakba. A tbla sorait az ExecuteReader() ltal visszaadott adatolvas (DataReader) objektummal olvassuk ki, de ezeket most nem konzolra rjuk ki, hanem egy j sort hozunk ltre az adattbla objektumban. Az j sor oszloprtkeire az oszlopok azon nevnek segtsgvel hivatkozunk (row["oszlopnv"]), amelyeket az adattbla objektum oszlopainak ltrehozsnl adtunk

16

Gregorics Tibor

Az ADO.NET osztlyai

meg. Ezeket az oszlop neveket azrt ismeri a row objektumunk, mert az adattbla objektum NewRow() metdusval hoztuk ltre. Az j sort vgl hozz adjuk az adattbla objektum Rows gyjtemnyhez. A feltlts vgn elhelyezett AcceptChanges() belltja a tbla sorainak sttuszt UnChanged-re, ami a sor trlse, mdostsa, beszrsa esetn vltozik meg.

DataRow
Tulajdonsg
RowState

Tpus
DataRowState

Magyarzat sttusz:(rgi)Unchanged,(j)Added, (trlt)Deleted,(mdostott)Modified, (mg/mr gyjtemnyen kvl)Detached Hivatkozs a begyaz DataTable objetumra A sor adott sorszm vagy nev oszlopnak rtkt adja meg Magyarzat Trli a sort Elfogadja illetve visszautastja az utols betlts vagy az AcceptChanges() legutbbi meghvsa utn keletkezett vltoztatsokat. Elindtja, lezrja illetve visszavonja a sor szerkesztst.

Table [sorszm] ["oszlopnv"]

DataTable object

Metdus
Delete() AcceptChanges() RejectChanges()

Visszatrsi tpus
void Void void

BeginEdit() EndEdit() CancelEdit()

Void void void

Adattbla objektum vltoztatsa


try{ // Egy sor trlse DataRow drd = dt.Rows[0]; drd.Delete(); // Egy sor mdostsa DataRow dru = dt.Rows[1]; dru["sea_distance"] = 666; // Egy j sor beszrsa DataRow dri = dt.NewRow(); dri["building_id"] = 4; dri["name"] = "name"; dri["city_id"] = 1; dri["street"] = "street"; dri["sea_distance"] = 4000; dri["shore_id"] = 1; dri["features"] = 0; dri["comment"] = "comment"; dt.Rows.Add(dri); }catch (DataException ex){ Console.WriteLine("Adatllomny hiba: {0}", ex.Message); }

17

Gregorics Tibor

Az ADO.NET osztlyai

A megoldsnak ez a rsze tetszs szerint kicserlhet annak megfelelen, hogy mit szeretnnk ezzel az alkalmazssal megmutatni. Itt most trlsre, mdostsra s beszrsra mutatunk pldt. Termszetesen egyszerre tbb trlst, mdostst s beszrst is elhelyezhetnk tetszleges sorrendben. Ez a kdrsz akkor dob DataException kivtelt, ha a vltoztatsok srtik az adattbla objektumnl definilt megszortsokat. Ha minden adatbzisbeli megszortst rvezettnk az adattbla objektumra, akkor, amennyiben itt nem keletkezik hiba, akkor az adatbzisba trtn visszamentsnek is sikerlnie kell (legalbb is, ami a megszortsok betartst illeti). Parancs objektumok definilsa a mentshez Parancs objektumokkal mr eddig is dolgoztunk. Az itt kzlt kdrszletben legfeljebb annyi jdonsg van, hogy paramterezett SQL parancsokat adunk meg benne. Az SQL parancs @ jellel kezdd paramtervltozkat tartalmaz, amelyeket Parameter objektumknt kell ltrehoznunk (a ltrehozsnl mi csak a paramter azonostjt s tpust adjuk meg). Ezeket a paramter objektumokat hozzadjuk a paramterezett SQL parancsot hordoz parancs objektumhoz. (Ugyanezt tettk korbban trolt eljrst tartalmaz parancs objektum esetben a trolt eljrs paramtervel.) A beszrs parancs objektuma:
SqlCommand insertcmd = con.CreateCommand(); insertcmd.CommandText = "INSERT INTO building " + "(building_id,name,city_id,street,sea_distance,shore_id, " + "features,comment) VALUES (@building_id,@name,@city_id, " + "@street,@sea_distance,@shore_id,@features,@comment)"; insertcmd.Parameters.Add(new SqlParameter( "@building_id", SqlDbType.Int)); insertcmd.Parameters.Add(new SqlParameter( "@name", SqlDbType.VarChar)); insertcmd.Parameters.Add(new SqlParameter( "@city_id", SqlDbType.Int)); insertcmd.Parameters.Add(new SqlParameter( "@street", SqlDbType.VarChar)); insertcmd.Parameters.Add(new SqlParameter( "@sea_distance", SqlDbType.Int)); insertcmd.Parameters.Add(new SqlParameter( "@shore_id", SqlDbType.Int)); insertcmd.Parameters.Add(new SqlParameter( "@features", SqlDbType.Int)); insertcmd.Parameters.Add(new SqlParameter( "@comment", SqlDbType.VarChar));

A trls parancs objektuma:


SqlCommand deletecmd = con.CreateCommand(); deletecmd.CommandText = "DELETE FROM building WHERE " + "building_id = @Original_building_id"; deletecmd.Parameters.Add( new SqlParameter("@Original_building_id", SqlDbType.Int));

18

Gregorics Tibor

Az ADO.NET osztlyai

A mdosts parancs objektuma:


SqlCommand updatecmd = con.CreateCommand(); updatecmd.CommandText = "UPDATE building " + "SET building_id = @building_id, name = @name, " + "city_id = @city_id, street = @street, " + "sea_distance = @sea_distance, shore_id = @shore_id, " + "features = @features, comment = @comment " + "WHERE building_id = @Original_building_id"; updatecmd.Parameters.Add(new SqlParameter("@building_id", SqlDbType.Int)); updatecmd.Parameters.Add(new SqlParameter("@name", SqlDbType.VarChar)); updatecmd.Parameters.Add(new SqlParameter("@city_id", SqlDbType.Int)); updatecmd.Parameters.Add(new SqlParameter("@street", SqlDbType.VarChar)); updatecmd.Parameters.Add(new SqlParameter("@sea_distance", SqlDbType.Int)); updatecmd.Parameters.Add(new SqlParameter("@shore_id", SqlDbType.Int)); updatecmd.Parameters.Add(new SqlParameter("@features", SqlDbType.Int)); updatecmd.Parameters.Add(new SqlParameter("@comment", SqlDbType.VarChar)); updatecmd.Parameters.Add(new SqlParameter("@Original_building_id", SqlDbType.Int));

Az adattbla objektum mentse a building tblba A ments fzisban vgig nzzk az adattbla objektum azon sorait, amelyek sttusza Added, Deleted vagy Modified, s ezeket az adatbzisbeli building tblban is megvltoztatjuk.

con.Open(); foreach(DataRow row in dt.Rows){ try { switch (row.RowState){ case DataRowState.Added: ... case DataRowState.Deleted: ... case DataRowState.Modified: ... } }catch (SqlException ex) { Console.WriteLine("Adatbzis hiba: {0}", ex.Message); Console.ReadLine(); } } con.Close();

19

Gregorics Tibor

Az ADO.NET osztlyai

A fenti ciklusmagban tallhat elgazs gaiban hasznljuk az elzleg definilt hrom paramterezhet parancs objektumot. Az elvgzend mvelettl fggen paramterezzk fel az insertcmd, a deletecmd, az updatecmd objektumokat az aktulis sor adataival a megkvnt mdon, majd hajtsuk vgre az ExecuteNonQuery() metdust.
case DataRowState.Added: insertcmd.Parameters["@building_id"].Value = row["building_id"]; insertcmd.Parameters["@name"].Value = row["name"]; insertcmd.Parameters["@city_id"].Value = row["city_id"]; insertcmd.Parameters["@street"].Value = row["street"]; insertcmd.Parameters["@sea_distance"].Value=row["sea_distance"]; insertcmd.Parameters["@shore_id"].Value = row["shore_id"]; insertcmd.Parameters["@features"].Value = row["features"]; insertcmd.Parameters["@comment"].Value = row["comment"]; int i = insertcmd.ExecuteNonQuery(); if(i==0) Console.WriteLine("Sikertelen beszrs"); break;

case DataRowState.Deleted: deletecmd.Parameters["@Original_building_id"].Value = row["building_id", DataRowVersion.Original]; int i = deletecmd.ExecuteNonQuery(); if(i==0) Console.WriteLine("Sikertelen trls"); break;

case DataRowState.Modified: updatecmd.Parameters["@Original_building_id"].Value = row["building_id", DataRowVersion.Original]; updatecmd.Parameters["@building_id"].Value = row["building_id"]; updatecmd.Parameters["@name"].Value = row["name"]; updatecmd.Parameters["@city_id"].Value = row["city_id"]; updatecmd.Parameters["@street"].Value = row["street"]; updatecmd.Parameters["@sea_distance"].Value=row["sea_distance"]; updatecmd.Parameters["@shore_id"].Value = row["shore_id"]; updatecmd.Parameters["@features"].Value = row["features"]; updatecmd.Parameters["@comment"].Value = row["comment"]; int i = updatecmd.ExecuteNonQuery(); if(i==0) Console.WriteLine("Sikertelen javts"); break;

20

Gregorics Tibor

Az ADO.NET osztlyai

Msodik megolds (adapterrel) Az elz megoldsban elemi eszkzkkel (Command) s sajt magunk ltal tervezett kdrsszel (ciklusokkal) vgeztk el az adatbzis betltst s visszamentst. A feladat egyszerbben is megoldhat egy megfelel tulajdonsgokkal rendelkez gynevezett adapter objektum bevezetsvel (DataAdapter). A msodik megolds az albbi rszekbl ll: 1. Egy adathalmazbeli adattbla objektum ltrehozsa. (nem vltozott) 2. Kapcsolati objektum s egy adapter objektum definilsa. 3. A building tbla letltse az adatbzisbl az adattbla objektumba. 4. Az adattbla objektum vltoztatsa (nem vltozott) 5. Ments az adattbla objektumbl az adatbzis building tbljba. Connection s DataAdapter objektumok ltrehozsa Termszetesen elszr most is a kapcsolati objektumot (con) definiljuk. Ezutn ltrehozzuk az adapter objektumot. Ez az objektum lnyegben ngy Command objektumot fog ssze: a letltsrt felels SelectCommand mellett a visszamentst meghatroz InsertCommand, DeleteCommand, UpdateCommand objektumokat. Az adapter Fill() metdusa olvassa be a sorokat az adatbzisbl egy adattbla objektumba vagy adathalmazba (ez a Fill paramterezsn mlik.) A visszamentst az Update() metdus a vgzi.

SqlDataAdapter
Tulajdonsg
SelectCommand InsertCommand DeleteCommand UpdateCommand ContinueUpdateError

Tpus
SqlCommand SqlCommand SqlCommand SqlCommand bool

Magyarzat Letltst meghatroz objektum j sor(oka)t adatbzisba r objektum Sor(oka)t adatbzisbl trl objektum Sor(oka)t adatbzisban mdost objektum Bellthat, hogy folytatdhat-e kivtel dobs nlkl az adatbzis frisstse hiba esetn Magyarzat Letlts Ments Az adatbzis szerkezett, megszortsait tlti le

Metdus
Fill() Update() FillScema()

Visszatrsi tpus
int int DataTable DataTable[]

Az adapter objektum ltrehozsa mg mindig meglehetsen nagy munka, de hasznlatval a letlts s a visszaments mr gyerekjtk.

21

Gregorics Tibor

Az ADO.NET osztlyai

SqlDataAdapter adapter = new SqlDataAdapter( "SELECT * FROM building",con); adapter.InsertCommand = new SqlCommand("INSERT INTO building" + "(building_id,name,city_id,street,sea_distance, shore_id," + "features,comment) VALUES (@building_id,@name, @city_id," + "@street,@sea_distance,@shore_id,@features,@comment)", con); adapter.InsertCommand.Parameters.Add(new SqlParameter( "@building_id", SqlDbType.Int, 0, "building_id")); adapter.InsertCommand.Parameters.Add(new SqlParameter( "@name", SqlDbType.VarChar, 0, "name")); adapter.InsertCommand.Parameters.Add(new SqlParameter( "@city_id", SqlDbType.Int, 0, "city_id")); adapter.InsertCommand.Parameters.Add(new SqlParameter( "@street", SqlDbType.VarChar, 0, "street")); adapter.InsertCommand.Parameters.Add(new SqlParameter( "@sea_distance", SqlDbType.Int, 0, "sea_distance")); adapter.InsertCommand.Parameters.Add(new SqlParameter( "@shore_id", SqlDbType.Int, 0, "shore_id")); adapter.InsertCommand.Parameters.Add(new SqlParameter( "@features", SqlDbType.Int, 0, "features")); adapter.InsertCommand.Parameters.Add(new SqlParameter( "@comment", SqlDbType.VarChar, 0, "comment")); adapter.DeleteCommand = new SqlCommand("DELETE FROM building" + "WHERE building_id = @Original_building_id", con); adapter.DeleteCommand.Parameters.Add(new SqlParameter( "@Original_building_id", SqlDbType.Int, 0, "building_id")); adapter.UpdateCommand = new SqlCommand("UPDATE building SET " + "building_id=@building_id, name=@name, city_id=@city_id, " + "street=@street, sea_distance=@sea_distance, shore_id = " + "@shore_id, features=@features, comment=@comment " + "WHERE building_id = @Original_building_id", con); adapter.UpdateCommand.Parameters.Add(new SqlParameter( "@building_id", SqlDbType.Int, 0, "building_id")); adapter.UpdateCommand.Parameters.Add(new SqlParameter( "@name", SqlDbType.VarChar, 0, "name")); adapter.UpdateCommand.Parameters.Add(new SqlParameter( "@city_id", SqlDbType.Int, 0, "city_id")); adapter.UpdateCommand.Parameters.Add(new SqlParameter( "@street", SqlDbType.VarChar, 0, "street")); adapter.UpdateCommand.Parameters.Add(new SqlParameter( "@sea_distance", SqlDbType.Int, 0, "sea_distance")); adapter.UpdateCommand.Parameters.Add(new SqlParameter( "@shore_id", SqlDbType.Int, 0, "shore_id")); adapter.UpdateCommand.Parameters.Add(new SqlParameter( "@features", SqlDbType.Int, 0, "features")); adapter.UpdateCommand.Parameters.Add(new SqlParameter( "@comment", SqlDbType.VarChar, 0, "comment")); adapter.UpdateCommand.Parameters.Add(new SqlParameter( "@Original_building_id", SqlDbType.Int, 0, "building_id"));

22

Gregorics Tibor

Az ADO.NET osztlyai

A building tbla letltse a DataTable objektumba A Fill() metdus rendre vgig megy a SelectCommand-ban megadott SQL parancs (vagy trolt eljrs) ltal letlttt sszes soron, s azokat elhelyezi a megfelelen ltrehozott adathalmazban. (Nem kezeltk le a Fill metdus ltal visszaadott rtket, amely a betlttt sorok szmt mutatja.)

try { adapter.Fill(ds, "building"); } catch (SqlException ex) { Console.WriteLine("Adatbzis hiba: {0}", ex.Message); Console.ReadLine(); return; }

A DataTable objektum mentse a building tblba Az Update() metdus a visszamentst vgzi. A metdus vgig nzi az adattbla vagy adathalmaz azon sorait, amelyek megvltoztak, s ezeket a vltozsokat (annak megfelelen, hogy jak, trltettek vagy mdosultak) az InsertCommand, DeleteCommand, UpdateCommand valamelyikvel visszamenti az adatbzisba. (Nem kezeltk le az Update metdus ltal visszaadott rtket, amely a visszamentett sorok szmt mutatja.)

try { adapter.Update(ds, "building"); } catch (SqlException ex) { Console.WriteLine("Adatbzis hiba: {0}", ex.Message); Console.ReadLine(); return; }

23

Gregorics Tibor

Az ADO.NET osztlyai

Harmadik megolds (varzslval) Most az adathalmaz (azon bell az adattbla) illetve az adapter objektum definilst egyszerstjk oly mdon, hogy segtsgl hvjuk a Visual Studio varzsljt, amivel gynevezett tpusos adathalmaz s tpusos adapter hozhat ltre. Adatforrs (DataSource) ksztse varzslval: 1. Vlasszuk ki a menbr Data menjbl vagy a DataSource View ablakbl az Add New DataSource ment! Ekkor megjelenik a Data Source Configuration Wizard ablak, s elindul az j adatforrs generlst vgz varzsl. 2. Jelljk meg az adat szrmazsi helynek a Database-t! 3. Vlasszuk ki vagy adjuk meg (New Connection ) az elrni kvnt adatbzisunk (ez most az Apartments) kapcsolati sztringjt! 3. Kvnsgunkra a kapcsolati sztringbl App.config nven generldik egy mr kitlttt Application Configuration File (lsd 1. fejezet). 4. Jelljk be az adatbzis letlteni kvnt rszt! (Ez a teljes building tbla.) Itt adhatjuk meg a ltrehozand gynevezett tpusos DataSet osztlynak nevt is. (Legyen ez BuildingDataSet.) A fenti lpsek hatsra ltrejn egy BuildingDataSet.xsd llomny, amely tbbek kztt az albbi szrmaztatott osztlyokat tartalmazza: - BuildingDataSet : DataSet - buildingDataTable : DataTable - buildingDataRow : DataRow - buildingDataAdapter (tartalmaz egy SqlDataAdapter objektumot) Ezek az osztlyok a projektnk rszt alkotjk. Megfelelen hivatkozva ezekre az osztlyokra ltrehozhatjuk azok pldnyaiknt a megoldshoz szksges objektumokat. (Vegyk szre, hogy ezek az osztlyok ms nvtrben jttek ltre.) rdemes belenzni a generlt kdba (BuildingDataSet.Designer.cs). Keressk meg, hol definilja a BuildingDataSet a tablebuilding adattagjt, amire building nvvel hivatkozhatunk majd; milyen oszlopai vannak a buildingDataTable osztlynak, hogy lehet rjuk hivatkozni, milyen tulajdonsgaik vannak; hol van a buildingDataAdapter osztlyban a szmunkra fontos SqlDataAdapter objektum SelectCommand, InsertCommand, DeleteCommand s UpdateCommand belltsa, hogyan hvhat meg a Fill() valamint Update() metdusa, s hol van elrejtve a megfelel SqlConnection objektum kezelse. A BuildingDataSet pldnyaknt egy gynevezett tpusos adathalmazt hozunk ltre. Ez abban klnbzik a kznsges adathalmaz objektumtl, hogy olyan tulajdonsgai is vannak, amelyek csak az Apartments adatbzis esetben rtelmezhet. Ltni fogjuk, hogyan lehet a tpusos adathalmaz building publikus adattagjval arra az adattblra hivatkozni, amelybe a building tbla adatait tlthetjk be, vagy hogyan lehet ennek a tblnak egy sort tartalmaz objektumnl publikus adattagknt hasznlni az oszlopneveket.

24

Gregorics Tibor

Az ADO.NET osztlyai

A harmadik megolds f modulja az albbi rszekbl ll: 1. A BuildingDataSet pldnyostsa s building tbljnak tnevezse (dt) 2. A buildingDataAdapter pldnyostsa 3. A building tbla letltse az adatbzisbl az adattbla objektumba (nem vltozott) 4. Az adattbla objektum vltoztatsa (nem vltozott) 5. Ments az adattbla objektumbl az adatbzis building tbljba. (nem vltozott)
BuildingDataSet ds = new BuildingDataSet(); BuildingDataSet.buildingDataTable dt = ds.building; BuildingDataSetTableAdapters.buildingTableAdapter adapter = new BuildingDataSetTableAdapters.buildingTableAdapter(); try { adapter.Fill(ds.building); } catch (SqlException ex) { Console.WriteLine("Adatbzis hiba: {0}", ex.Message); Console.ReadLine(); return; }

Kihasznlva a tpusos adathalmaz elnyeit tovbb egyszersthetjk a building tbla karbantartst vgz kdrszt is. Figyeljk meg, hogyan lehet hivatkozhatunk egy tpusos adatsor (BuildingDataSet.buildingRow) objektum mezire (oszlopaira). (A dt vltoz helyett ds.building-et runk.).
try { // Egy sor trlsea BuildingDataSet.buildingRow drd = (BuildingDataSet.buildingRow)ds.building.Rows[0]; drd.Delete(); // Egy sor mdostsa BuildingDataSet.buildingRow dru = (BuildingDataSet.buildingRow)ds.building.Rows[1]; dru.sea_distance = 666; // Egy sor beszrsa BuildingDataSet.buildingRow dri = (BuildingDataSet.buildingRow)ds.building.NewRow(); dri.building_id = 4; dri.name = "name"; dri.city_id = 1; dri.street = "street"; dri.sea_distance = 4000; dri.shore_id = 1; dri.features = 0; dri.comment = "comment"; ds.building.Rows.Add(dri); }catch (DataException ex){ Console.WriteLine("Adatllomny hiba: {0}", ex.Message); }

25

Gregorics Tibor

Adattbla karbantarts

Adattbla karbantarts
ADATTBLA KARBANTARTS ........................................................................................ 26
1.DURVA VLTOZAT ......................................................................................................................................... 27

Tervez nlkl .................................................................................................................. 27 Objektumok Tervezvel, tulajdonsgaik kddal............................................................... 30 Mindent a Tervezvel ....................................................................................................... 31 Egyetlen hzssal ............................................................................................................. 32
2. ADATTBLA OSZLOPAINAK TESTRE SZABOTT MEGJELENTSE...................................................................... 34

Azonost elrejtse s rtknek automatikus generlsa................................................ 34 Idegenkulcs rtknek megjelentse, kombinltdobozos kivlasztsa ............................ 35 Egyedi cellaformk........................................................................................................... 36
3. HIBAELLENRZS ......................................................................................................................................... 45

Mezellenrzs ................................................................................................................. 45 Sorellenrzs .................................................................................................................... 47 Tblaellenrzs ................................................................................................................ 47 Adatbzis ellenrzs......................................................................................................... 47 Az albbiakban olyan grafikus fellet alkalmazsokat mutatunk, amelyek egy adattbla karbantartsnak problmjt jrjk krl. Megismerjk, hogyan lehet felhasznli felletet alkot vezrlkkel egy adathalmaz objektum adatait megjelenteni, mdostani.1 Nem treksznk ezen osztlyok minden rszletre kiterjed ismertetsvel ezt mind nyomtatott, mind online szakirodalmakban megtallhatjuk , helyette az alkalmazsaikra helyezzk a hangslyt. A feladatokat egy kpzelt utazsi iroda apartman-foglalsi tevkenysghez hasznlt Apartments adatbzisra fogalmazzuk meg. Ebben a fejezetben ennek az adatbzisnak az pletek lersra szolgl building nev tbljnak karbantartsrl lesz sz, de mivel ez idegen-kulcs kapcsolatban ll kt msik tblval, gy azokkal is szmolnunk kell.
CREATE TABLE building ( building_id INTEGER PRIMARY KEY, name VARCHAR(30), city_id INTEGER NOT NULL, street VARCHAR(30) NOT NULL, sea_distance INTEGER, shore_id INTEGER, features INTEGER, comment VARCHAR(100), FOREIGN KEY (city_id) REFERENCES city, FOREIGN KEY (shore_id) REFERENCES shore ); CREATE TABLE city ( city_id INTEGER PRIMARY KEY, name VARCHAR(30), ); CREATE TABLE shore ( shore_id INTEGER PRIMARY KEY, type VARCHAR(10), );

Az osztlyok bemutatsnl John Sharp Visual C# 2005 Lpsrl lpsre c. knyvre (2005, SZAK Kiad.) tmaszkodtam.

26

Gregorics Tibor

Adattbla karbantarts

Feladat: Ksztsnk olyan grafikus fellet alkalmazst, amely lehetsget ad a building tbla karbantartsra! Fokozatosan mdostjuk megold programot egyfell abbl a clbl, hogy annak jbli ellltsa minl kevesebb terhet rjon a programozra, msfell azrt, hogy a felhasznli bartsgossg szempontjainak minl jobban megfeleljen (ne kelljen a felhasznlnak egyetlen azonostkdot sem ismerni/megadni, j sor beszrsnl tltsk ki a mezket alaprtelmezett rtkekkel, csak rtelmes, hibt nem okoz adatbevitelt engedlyezznk. Elszr az alkalmazs puritn, durva verzijt ksztjk el. Ez mg semmilyen hibakezelst nem vgez majd, az adattbla sorai egysgesen TextBox-szeren mdosthatk, a felleten minden adat abban a formban jelenik meg, ahogy azt a tbla tartalmazza, azaz a knyelmes hasznlatot zavar bels azonostkat s kdokat is fogunk ltni. Ennl fogva ez az alkalmazs teljesen ltalnos, brmilyen adattbla karbantartsa esetben elkszthet. A hangslyt arra helyezzk, hogy bemutassunk nhny klnbz technikt az alkalmazs ltrehozsra. Msodik lpsben hozzigaztjuk az alkalmazst a konkrt feladathoz: egyedi megjelenssel, majd a harmadik lpsben a hiba ellenrzssel. 1. Durva vltozat A kvetkezkben azt mutatjuk meg, hogyan lehet egy gynevezett DataGridView vezrl segtsgvel egy DataTable adatait megtekinteni s mdostani. Ugyanannak a megoldsnak tbb ellltsi mdjt is megmutatjuk: elszr egyltaln nem hasznljuk a Visual Studio Designer-t, ms nven Tervezt, utna bizonyos lpseket mr annak segtsgvel vgznk el, vgl az egsz alkalmazst a Tervezvel ksztjk. Minden esetben azzal kezdjk a munkt, hogy egy Windows Application projektet indtunk, amihez hozzadunk egy BuildingDataSet nev adatforrst (Data Source, lsd elz fejezet) az Apartments adatbzis building tbljrl. Ennek kvetkeztben lesz egy BuildingDataSet tpusos DataSet osztlyunk, s a BuildingDataSetTableAdapters alnvtrben egy buildingTableAdapter tpusos adapterosztlyunk. Tervez nlkl A feladat megoldshoz ngy objektumra van szksgnk. Egy adathalmaz (DataSet) objektumra, amelyben a building tbla adatait troljuk; egy adapter objektumra, amellyel a program legelejn az adatbzisbl letltjk az adatokat s egy nyomgomb (Button) hatsra visszamentjk azokat; egy adatrcs (DataGridView) vezrlre, amelyen keresztl a felhasznl az adathalmazbeli adatokat nzegetheti, mdosthatja. Az adathalmaz s adapter objektumokat a korbban generlt tpusos DataSet s tpusos DataAdapter osztlyokbl pldnyostjuk, a msik kt objektumot pedig a megfelel System.Windows.Forms-beli osztlyokbl.

public partial class Form1 : Form { private BuildingDataSet buildingDataSet; private BuildingDataSetTableAdapters.buildingTableAdapter buildingTableAdapter; private DataGridView buildingDataGridView; private Button buttonSave;

27

Gregorics Tibor

Adattbla karbantarts

Az rlap-osztly konstruktorban az InitializeComponent() metdushvs utn elszr belltjuk az rlap mrett, majd a buildingDataGridView vezrlt hozzuk ltre megadva nhny, az elhelyezkedsre vonatkoz tulajdonsgt. Ugyanezt tesszk a buttonSave nyomgombbal is, s ennek Click esemnyhez deleglunk egy esemnykezel fggvnyt is.
using System.Drawing; ... public Form1() { InitializeComponent(); ClientSize = new Size(540, 350); buildingDataGridView = new DataGridView(); buildingDataGridView.Location = new Point(20, 40); buildingDataGridView.Size = new Size(500, 250); Controls.Add(buildingDataGridView); buttonSave = new Button(); buttonSave.Location = new Point(230, 300); buttonSave.Size = new Size(80, 25); buttonSave.Text = "Save"; buttonSave.Click += new System.EventHandler(buttonSave_Click); Controls.Add(buttonSave);

Ezt kveten ltrehozzuk a buildingDataSet s buildingTableAdapater objektumokat. Most kvetkezik taln a kd legrdekesebb, leglnyegesebb rsze. A buildingDataGridView objektum DataSource tulajdonsgt rlltjuk a buildingDataset-re, DataMember tulajdonsgt a building tblra (annak nevre). Ennek hatsra kapcsoldik ssze az adatrcs az adathalmazban trolt building adattblval. Ezutn az adatrcsban bekvetkezett vltozs az adathalmazban is rgtn ltszani fog. Az adatrcshoz definilni kell azokat az oszlopokat is, amelyeken keresztl megmutatja az adattbla oszlopait. Ezt a fradsgos s unalmas kdolst azonban megszhatjuk a buildingDataSet ScemaSerializationMode tulajdonsgnak belltsval. Ennek hatsra a building tbla oszlopai automatikusan tmsoldnak az adatrcs oszlopaiv.
buildingDataSet = new BuildingDataSet(); buildingTableAdapter = new BuildingDataSetTableAdapters.buildingTableAdapter(); buildingDataSet.SchemaSerializationMode = System.Data.SchemaSerializationMode.IncludeSchema; buildingDataGridView.DataSource = buildingDataSet; buildingDataGridView.DataMember = buildingDataSet.building.TableName; buildingTableAdapter.Fill(buildingDataSet.building); }

28

Gregorics Tibor

Adattbla karbantarts

Legvgl a konstruktorban betltjk az adatbzis building tbljt a buildingDatasetbe a buildingTableAdapater Fill() metdussal. Ennek fordtottja a ments, amely a buttonSave nyomgomb lenyomsra kvetkezik be. Ehhez a buildingTableAdapater Update() metdust a nyomgomb Click esemnykezeljben helyezzk el.
private void buttonSave_Click(object sender, EventArgs e) { buildingTableAdapter.Update(buildingDataSet); } }

Az alkalmazst ezutn fordtjuk s futtatjuk. Az alkalmazs mkdik, de mg korntsem felel meg a feladatban megfogalmazott elvrsoknak (hibs adatbevitel esetn kezeletlen kivtelt dob, bels azonostkat mutat).

29

Gregorics Tibor

Adattbla karbantarts

Objektumok Tervezvel, tulajdonsgaik kddal

A VS Tervezjnek hasznlatval lnyegesen lervidthet a kdols. Mr azltal, hogy az rlap komponenseit a Tervezvel helyezzk el, sok idt sprolunk. (Az adatforrs ltrehozsa s egy fordtsi lps elvgzse utn a BuildingDataSet s a buildingTableAdapter vlaszthat komponensknt felkerl a ToolBox-ban, gy mint a DataGridView vagy a Button.) Hzzuk r a tervez felletre drag&drop technikval mind a ngy komponenst. A kdban automatikusan ltrejnnek a komponensek objektumai. Ekkor a sajt kdrsz konstruktorban mindssze az albbiakat kell rnunk. (A buttonSave_Click() esemnykezel ugyanaz, mint korbban.)

public Form1() { InitializeComponent(); buildingDataGridView.DataSource = buildingDataSet; buildingDataGridView.DataMember = buildingDataSet.building.TableName; buttonSave.Click += new System.EventHandler(buttonSave_Click); buildingTableAdapter.Fill(buildingDataSet.building); }

30

Gregorics Tibor

Adattbla karbantarts

Mindent a Tervezvel Az Olvas jl tudja, hogy egy nyomgomb Click esemnyhez gy is deleglhat kezelfggvnyt, ha duplt kattint a nyomgombon vagy a Properties ablak esemnypaneljnek Click sorban. Nyilvn azon sem lepdik meg, hogy a buildingDataGridView DataSource tulajdonsgt is be lehet lltani a Properties ablakban (ami a Tervez nzetben kijellt adatrcs jobb fels sarkn tallhat gynevezett SmartTag bekapcsolsval felnyl ablakban is megtallhat). A DataSource tulajdonsg belltsakor egy jabb ablak nylik fel. Mindkt esetben egy rdekes dolog trtnik: ltrejn egy j objektum. Ez egy gynevezett adatkapcsol objektum, amely bekeldik a buildingDataGridView s els esetben a buildingDataSet, a msik esetben annak building tblja kz. Ennek generlt neve az els esetben a buildingDataSetBindingSource, a msodikban buildingBindingSource lesz. Ha megnzzk a tulajdonsgait, akkor lthatjuk, hogy most az DataSource tulajdonsga mutat a buildingDataSetre, az adatrcs DataSource tulajdonsga pedig erre az j adatkapcsol objektumra. (Az els esetben mg a DataMember tulajdonsgot is be kell majd lltani a building-re vagy a rcsnl, vagy az adatkapcsol objektumnl.)

Ebben ktflekppen is bellthatjuk az adatforrst: els esetben a buildingDataSet-et, msodik esetben annak building tbljt megjellve.

Ennek a megoldsnak elnye, hogy mr tervezsi idben lthatak az adatrcsban az adattbla oszlopai, gy azok tulajdonsgai is alakthatak a Tervezvel. Az adatkapcsol objektum jelentsge azonban csak akkor rthet meg, ha az adatrcson kvl ms vezrlkben is ltni akarjuk a building tbla adatait. Vegynk fel pldul az rlapra egy szvegdobozt (TextBox) s egy listadobozt (ListBox). lltsuk be a szvegdoboz DataBindigs.Text tulajdonsgt name-re. (Kzzel rt kd esetn: textBox.DataBindings.Add(new Binding("Text", buildingBindingSource, "name", true)); ). Rendeljk a listadoboz DataSource tulajdonsghoz a buildingBindingSource -ot, DisplayMember tulajdonsghoz pedig a street-et. Futtassuk az alkalmazst. Azt ltjuk, hogy egyszerre s szinkronban vltoznak az adatok az adatrcsban, a szvegdobozban s a listadobozban. Visszatrve az eredeti alkalmazsunkhoz, annak ksznheten, hogy ott minden belltst a Tervezvel csinltunk mindssze kt sort kell a programba kzzel belerni. Az adatbzis building tbljt betlt Fill() metdushvst (a konstruktorba az InitializeComponent() hvsa utn) s a visszamentst vgz Update() metdushvst (a nyomgomb esemnykezeljbe). 31

Gregorics Tibor

Adattbla karbantarts

Egyetlen hzssal Az alkalmazsunk egyetlen drag&drop mozdulattal is elkszthet. Hzzuk r a Data Source nzet building tbljt az rlapra. Ennek hatsra minden felkerl r, st egy gynevezett navigl sv is megjelenik az rlapon a ments nyomgombbal egytt.

A kdba semmit nem kell belernunk, ugyanis az mr a Fill() s Update() metdushvsokat is tartalmazza. Ebben az esetben a Fill() hvsa nem a konstruktorban, hanem az rlap mindenkori betltsekor bekvetkez Load esemnykezeljben tallhat, az Update()hvst pedig megelzi az aktulis szerkesztsi folyamat validlsa s lezrsa.

32

Gregorics Tibor

Adattbla karbantarts

Hangslyozzuk, hogy az alkalmazsunk mkdse mg mindig ugyanaz, mint amit az els verzinl lttunk. Ez azt is jelenti, hogy tovbbra sem kezeli a hibs adatbevitel. A fellet mg most is olyan bels azonostkat mutat, amivel a felhasznl nem igen tud mit kezdeni, legfeljebb hibsan megadni. A hibaellenrzs hinya miatt az alkalmazs hasznlata kzben tbbfle kezeletlen kivtel keletkezhet. Mieltt az alkalmazsunkat tovbbfejlesztennk meg kell jegyeznnk, hogy a bemutatott drag&drop technikval a kivlasztott adattblt nemcsak adatrccsal jelenthetjk meg. Az adattbla egy sornak mezit nll vezrlkben is kezelhetjk (ezek formjt a Data Source nzetben lehet belltani). Ezek a vezrlk az adatrccsal egy idben is fenn lehetnek az rlapon, mert szinkronizlt mkdsket a generlt adatkapcsol objektum felgyeli.

Ez egy kzkedvelt vltozata a tblakarbantartsnak, klnsen, ha az adatrcsot csak nzegetsre, egy sor kivlasztsra hasznljuk (azaz az adatrcs ReadOnly tulajdonsg), az aktulis illetve az res sor szerkesztse pedig a meznknti vezrlkben trtnik.

33

Gregorics Tibor

Adattbla karbantarts

2. Adattbla oszlopainak testre szabott megjelentse Induljunk ki az elzekben mr elksztett alkalmazsbl azzal a klnbsggel, hogy egy j ApartmentsDataSource adatforrs hozzadsakor nemcsak a building tblt, hanem a city s shore tblkat is megjelljk az adatbzisban. Ekkor a tpusos DataSet osztlyba bekerl e kt utbbi adattbla, amelyekhez kln-kln tpusos adapter osztlyok jnnek ltre. Az alkalmazst ugyangy ksztjk el, mint korbban. Tervez nzetben az ApartmentsDataSource adatforrs building tbljt drag&drop technikval az rlapra hzzuk. Vegyk ezek utn sorra, milyen mdostsokat kell az alkalmazs durva vltozatn elvgezni. 1. A buiding_id oszlopot el kell rejtennk, hogy itt ne mdosthassa a felhasznl (ezt a ReadOnly tulajdonsgval is bellthatnnk), s ne is lssa, hiszen ez gysem fejez ki szmra a feladat szempontjbl hasznos informcit. Gondoskodnunk kell ugyanakkor arrl, hogy egy j sor beszrsakor a buiding_id rtke automatikus generldjon. (Ezt sokszor az adatbzisnl, teht a szerver oldalon megrt trolt eljrs vgzi, mi azonban most a kliens oldalon oldjuk meg ezt.) 2. A city_id oszlopban a telepls-azonost helyett mindig az annak megfelel telepls neve jelenjen meg. Egy telepls megvltoztatsakor nem az azonostt, hanem annak nevt szeretnnk megadni, de azt a city tblban trolt teleplsneveket tartalmaz listbl, hogy vletlenl se rhassunk be olyan nevet, ami nincsen. (Egy msik modulban, a city tbla karbantartsa keretben lehetne j teleplst felvenni az adatbzisba.) Az oszlop stlusa ne szvegdoboz legyen, hanem a fenti funkcionalitst tmogat kombinltdoboz (ComboBox), amit a keretrendszer kszen szolgltat szmunkra. 3. A shore_id oszlopnl ugyanaz a helyzet, mint a city_id esetben. 4. A features oszlopban nem szmkdot akarunk ltni, hanem az ennek keretben bejellt (bejellhet) plet-tulajdonsgok listjt, mondjuk egy ellenrzdoboz-lista (CheckedBoxList) formjban. Ehhez neknk kell megrni azt a programrszletet, amely a szmkd alapjn kitlti az ellenrzdoboz-listt, s fordtva, az ellenrzdoboz-lista alapjn elkszti az adattblba rand szmkdot. Ez egy egyedi oszlop definilst ignyli. 5. A street oszlop az adatbzisban nem tartalmazhat nullrtket, ezrt ennek kitltst ktelezv kell tennnk. Ezt az ignyt azonban csak a hibakezelsnl fogjuk kielgteni. Nzzk meg most ezeket a lpseket rszletesen! Azonost elrejtse s rtknek automatikus generlsa Egy oszlop elrejtse, azaz az adatrcsbl val kivtele nagyon egyszer. Kattintsunk a Tervez nzetben az adatrcs jobb fels sarkban lev SmartTag-re, s a felnyl ablakban vlasszuk ki az Edit Columns opcit. A megjelen Edit Columns ablakban trlhetjk (Remove) az adatrcsbl a building_id oszlopot. Az automatikus rtkgenerlshoz jelljk ki a Tervez nzetben az ApartmentsDataSet komponenst, s annak SmartTag-jre kattintva vlasszuk ki a felnyl ablak Edit in DataSet Designer opcijt. (Ugyanezt a hatst rjk el a Solution explorer-beli ApartmentsDataSet.xsd llomny kinyitsval.) Ekkor megjelenik a tpusos adathalmaz 34

Gregorics Tibor

Adattbla karbantarts

mindhrom tblja. Jelljk ki a building tbla building_id oszlopt s a Properties ablakban lltsuk be az albbi tulajdonsgot: AutoIncrement : true Idegenkulcs rtknek megjelentse, kombinltdobozos kivlasztsa Ismt az adatrcs Edit Columns ablakban dolgozunk. Jelljk ki a city_id oszlopot. lltsuk be az albbi tulajdosgokat: ColumnType: DataSource: ValueMember: HeaderText: DataGridViewComboBoxColumn Other Data Sources/ Project Data Sources/ ApartmentsDataSet/ city city_id city

DisplayMember: name

DisplayStyleForCurrentCellOnly: true A legutols tulajdonsg az inaktv cella megjelenst mdostja: csak akkor ltszdjon errl az oszloprl, hogy ennek celli kombinltdobozok, amikor a cellra rlpnk. Ne lepdjnk meg azon, hogy kzben jabb adatkapcsolat objektum jelent meg az alkalmazsunkban: ez kti az adathalmaz city tbljt a city_id oszlop kombinltdoboznak listjhoz. Az oszlop belltsakor mg eljtszhatunk az oszlopszlessgnek belltsval. A fentieket rtelemszeren megismteljk a shore_id oszlopra is.

35

Gregorics Tibor

Adattbla karbantarts

Egyedi cellaformk Alaphelyzetben az adatrcs csak nhny oszlop-tpussal rendelkezik. Ezeket az adatrcs oszlopai ColumnType tulajdonsgnak belltsnl megjelen kombinltdobozban olvashatjuk. Ha ezektl eltr cellaformj oszlopot szeretnnk definilni, akkor kzelebbrl meg kell ismerkednnk az adatrcs bels vilgval. Mivel az egy oszlopba tartoz cellk azonos tpusak, ezrt az oszlopra jellemz cellatpust egy DataGridViewColumn osztlybl szrmaztatott osztlyban rhatjuk le. Ennek az osztlynak egy objektumt kell az adott oszlophoz hozzrendelni, amelynek a CellTemplate tulajdonsgbl olvashat ki az oszlophoz tartoz cellk tpusa. Az oszlophoz tartoz cellkat egy DataGridViewCell osztlybl szrmaztatott osztly rja le. Amikor az adatrcs jabb sorral bvl, akkor az adott oszlophoz tartoz cella ennek a szrmaztatott osztlynak j objektuma lesz. Ez az objektum felel a cella megjelensrt passzv illetve aktv llapotban, s az utbbi esetben termszetesen ismernie kell azt a vezrlt, amelynek mkdse sorn a cella rtkt (Value) meg lehet vltoztatni. Ez egy gynevezett szerkeszt-vezrl osztlynak a pldnya, amely osztlynak a DataGridViewEditingControl osztlybl kell szrmaznia, amely biztostja a cella rtknek szerkeszthetsgt. DataGridView Columns CellTemplate * DataGridViewColumn

DataGridViewCell Value

DataGridViewEditingControl

Neknk most egy olyan oszloptpusra van szksgnk, amely lehetv teszi, hogy egy cellban tetszleges szm szvegesen megadott sszetevt felsoroljunk (az pletek esetben ezek a parkol hely, kert, szmedence, strandszolgltats), s lehetv teszi, hogy ezek kzl brmelyiket egyszerre akr tbbet is megjelljnk. Erre mg tallhatunk is gyri vezrlt (ilyen a CheckedListBox), de neknk a megjellseket egsz szm formjban kdolva kell visszaadni, s fordtva, egy egsz szm alapjn be kell tudni jellnnk a megfelel sszetevket. Ehhez ksztnk egy egyedi vezrlt, amely osztlyt a CheckedListBox osztlybl szrmaztatjuk, hogy felhasznlhassuk annak mr meglev kdjt. Kiegsztjk ezt a szksges szmtsokkal. Ezutn ebbl elksztjk a sajt DataGridViewEditingControl osztlyunkat, amelyhez legyrtjuk a megfelel sajt DataGridViewCell s DataGridViewColumn osztlyokat is. Vgl a VS tervezjvel hozzrendeljk a megfelel adatrcs oszlophoz azt ez j oszloptpust.

36

Gregorics Tibor

Adattbla karbantarts

1. Egyedi szerkeszt-vezrl ksztse A vezrlnk alapjt teht egy ellenrzdoboz-lista alkotja (CheckedListBox), amit kiegsztnk egy tulajdonsggal (Value), ami a megjellseket kdol egsz szm lesz. Ennek a szmnak 2-komplemens kdjban a bitek mutatjk meg azt, hogy egy sszetev meg van-e jellve (1-es bit), vagy nincs (0-s bit). gy a 0 egsz szm azt kdolja, amikor egyik sszetev sincs megjellve, az 1 azt, amikor csak a legutols, a kett hatvnyai azt, amikor pontosan egy, s pldul a 6 azt, amikor az utols eltti s az azeltti. Az j vezrl osztlyt a CheckedListBox osztlyra tmaszkodva ktflekppen is elkszthetjk: egy CheckedListBox vezrlt adattagknt tartalmaz (kompozci vagy ers tartalmazsi kapcsolat) vezrl osztllyal (azaz a MyDataGridViewColumn-bl szrmaztatva), vagy kzvetlenl a CheckedListBox osztlybl szrmaztatva. Adjunk egy Windows Control Library projektet a solution-hoz mondjuk MyDataGridViewColumn nven. Ennek egy osztlya lesz a FeaturesSettingControl, amit a CheckedListBox-bl szrmaztatunk. Ehhez fel kell venni a projekt referencii kz a .NET/System.Windows.Forms-ot, s meg kell azt hivatkozni a using direktvval. A konstruktorban a CheckedListBox kt tulajdonsgt lltjuk be.

... using System.Windows.Forms; namespace MyDataGridViewColumn { public class FeaturesSelectingControl : CheckedListBox { public FeaturesSelectingControl():base() { CheckOnClick = true; Click += new EventHandler(checkedListBox_Click); }

A FeaturesSelectingControl osztlyt egsztsk ki kt tulajdonsggal. Az egyikkel le lehet krdezni s meg lehet vltoztatni a vezrl rtkt, azt a szmkdot, amely a listban megjellt sszetevktl fgg.

public int Value { get { return Code(); } set { Decoding(value); } }

A msik tulajdonsggal le lehet krdezni s jra lehet definilni a checkedListBox-ban megjelen sszetevk nevt.

37

Gregorics Tibor

Adattbla karbantarts

public object[] List { get { object[] list = new object[this.Items.Count]; int i = 0; foreach (object item in Items) { list[i] = item; ++i; } return list; } set { this.Items.Clear(); if (value != null) this.Items.AddRange(value); } }

A kdols s dekdolst vgz privt metdusok egy egsz szm rtknek kettes szmrendszerbeli alakjnak, illetve kettes szmrendszerbeli alak egsz rtknek meghatrozsra plnek. A kdolshoz s dekdolshoz bitmveleteket (bitenknt vagy, lptets) hasznlunk.

private void Decoding(int code) { int n = this.Items.Count - 1; while (code != 0) { checkedListBox.SetItemChecked(n, (code & 1) == 1); code >>= 1; --n; } for (; n >= 0; --n) checkedListBox.SetItemChecked(n, false); }

private int Code() { int code = 0; int n = checkedListBox.Items.Count - 1; foreach (int k in checkedListBox.CheckedIndices) code |= (1 << n - k); return code; }

38

Gregorics Tibor

Adattbla karbantarts

Vgl elksztjk a Click esemnykezelt. Ennek egyetlen feladata, hogy meghvja azt az OnValueChanged() virtulis metdust, amelyet majd a most ksztett osztlybl szrmaztatott osztlyban lesz lehetsgnk fellrni.

private void checkedListBox_Click(object sender, EventArgs e) { OnValueChanged(e); } protected virtual void OnValueChanged(EventArgs eventargs) { }

2. j adatrcs-oszlop tpus definilsa Ha megvan a kvnt vezrl, akkor fggetlenl attl, hogy sajt vagy gyri el kell belle kszteni egy j adatrcs-oszlop tpust. Ezt a munkt rdemes kln projektben vgezni, gy az jrafelhasznlhatsg egyszer lesz. A projekt neve legyen DataGridViewFeaturesColumn. Ez a projekt hrom osztlyt fog tartalmazni: a DataGridViewColumn osztlybl szrmaz DataGridViewFeaturesColumn osztlyt, a DataGridViewTextBoxCell osztlybl szrmaz a DataGridViewFeaturesCell osztlyt s a FeaturesEditingControl osztlyt, amelyet egyszerre kt osztlybl is szrmaztatni kellene, egyrszt a FeaturesSelectingControl, msrszt a DataGridViewEditingControl osztlyokbl. Mivel azonban a C# nem tmogatja a tbbszrs rkldst2, a FeaturesEditingControl osztly a DataGridViewEditingControl osztlybl val szrmaztats helyett implementlni fogja az IDataGridViewEditingControl interfszt. Az itt begrt osztlyok definilshoz rdemes megnzni a sgban (DataGridView/ Customization), hogyan szoktk az ilyen jelleg problmkat megoldani, s annak mintjra kszthetjk el a sajt osztlyainkat. Projektnk referencii kz vegyk fel a MyDataGridViewColumn projektet, hiszen abban definiltuk a FeaturesSelectingControl osztlyt.

A C# nem tmogatja a tbbszrs rkldst; tbb osztlybl csak gy lehet szrmaztatni, ha azok kztt csak egy rendes osztly van, a tbbi pedig gynevezett interfszt. Az interfsz nem a programnyelv fell szemllve tulajdonkppen egy olyan absztrakt osztly, aminek nincsenek adattagjai, s az sszes metdusa is absztrakt. Az ilyen nagyon absztrakt osztlybl val szrmaztats, az gynevezett implementls esetn az sszes metdushoz implementcit kell rni.

39

Gregorics Tibor

Adattbla karbantarts

A DataGridViewFeaturesColumn osztly Ezt az osztlyt DataGridViewColumn-bl szrmaztatjuk, hiszen rendelkeznie kell az adatrcs-oszlopok olyan szoksos tulajdonsgaival, mint az oszlop fejlce, az oszlop szlessgnek belltsa, vagy annak az informcinak trolsa (CellTemplate), amely megmondja az adatrcsnak, hogy egy adott sor adott oszlopnl milyen tpus cella jelenjen meg. Az albb bemutatott osztly kt egyedi elemet mutat az sosztlyhoz kpest. Van egy publikus teht kvlrl bellthat List adattagja, amely alapjn a cellban megjelentend egyedi FeaturesSelectingControl vezrlnk List tulajdonsgt lltjuk be (ettl fgg, hogy milyen szvegek jelennek meg a CheckedListBox-ban). A msik a CellTemplate tulajdonsg felldefinilsa gy, hogy annak az ltalunk definiland DataGridViewFeaturesCell osztlyt lehessen megadni.

public class DataGridViewFeaturesColumn: DataGridViewColumn { public DataGridViewFeaturesColumn() :base(new DataGridViewFeaturesCell()){ } public override DataGridViewCell CellTemplate { get{ return base.CellTemplate; } set { if (value != null && !value.GetType(). IsAssignableFrom(typeof(DataGridViewFeaturesCell))) { throw new InvalidCastException( "Must be a FeatureCell"); } base.CellTemplate = value; } } public virtual object[] List { get { return((DataGridViewFeaturesCell)this.CellTemplate) .List; } set {((DataGridViewFeaturesCell)this.CellTemplate) .List = value;} } }

40

Gregorics Tibor

Adattbla karbantarts

A DataGridViewFeaturesCell osztly Ezt az osztlyt a DataGridViewTextBoxCell osztlybl szrmaztatjuk azrt, hogy a cellnk inaktv llapotban egy kznsges szvegdoboznak ltszdjon. Ilyenkor az adatbzisban szerepl kdot ltjuk a cellban, de ha rkattintunk, akkor megjelenik az ellenrzdobozos-listnk, amelyet szerkeszthetnk. Ez termszetesen nem szp megolds, amelyen a Paint metdus megfelel fellrsval tudnnk vltoztatni, de ne felejtsk el, hogy most mg csak az els vltozatot kszjk. Az igazn lnyeges rsze ennek az osztlynak az InitializeEditingControl() metdus fellrsa. Ennek kt funkcija van. Egyrszt rtkl adja a DataGridViewFeaturesColumn-ban definilt List tulajdonsgot az egyedi vezrlnket kpvisel FeaturesEditingControl (ennek defincijt mindjrt medmutatjuk) List tulajdonsgnak, msrszt a cella Value tulajdonsgt a FeaturesEditingControl Value tulajdonsgnak. Ezen kvl mg hrom tulajdonsgt kell fellrni az osztlynak.
class DataGridViewFeaturesCell: DataGridViewTextBoxCell { public DataGridViewFeaturesCell() : base() { } public override void InitializeEditingControl( int rowIndex, object initialFormattedValue, DataGridViewCellStyle dataGridViewCellStyle) { base.InitializeEditingControl( rowIndex, initialFormattedValue,dataGridViewCellStyle); FeaturesEditingControl ctl = DataGridView.EditingControl as FeaturesEditingControl; DataGridViewFeaturesColumn fc; DataGridViewColumn dgvc = OwningColumn; if (dgvc is DataGridViewFeaturesColumn) { fc = dgvc as DataGridViewFeaturesColumn; ctl.List = fc.List; ctl.Value = (Value == null || Value.ToString() == "") ? 0 : (int)Value; } } public override Type EditType { get{ return typeof(FeaturesEditingControl); } } public override Type ValueType { get{ return typeof(int); } } public override object DefaultNewRowValue { get{ return ""; } } }

41

Gregorics Tibor

Adattbla karbantarts

A FeaturesEditingControl osztly Ennek az osztlynak egyszerre kt osztlyra is hasonltani kell. Egyrszt az ltalunk krelt a osztlyra, hiszen azt akartuk a adatrcs-cellban megjelenteni. Msrszt olyannak kell lennie, mint a DataGridViewEditingControl osztly, hiszen ilyenre van szksge az elbb definilt DataGridViewFeaturesCell osztlynak. A .NET rendelkezik a DataGridViewEditingControl osztlynak az interfsz IDataGridViewEditingControl interfsszel, amit a prjval, az FeaturesEditingControl implementlni fog, de ennek az a kvetlkezmnye, hogy nagyon sok olyan metdust is tartalmaz, amelynek csak annyi a szerepe, hogy van.
FeaturesSelectingControl

class FeaturesEditingControl: MyDataGridViewColumn.FeaturesSelectingControl, IDataGridViewEditingControl { protected DataGridView dataGridView; protected bool valueChanged = false; protected int rowIndex; public FeaturesEditingControl(): base() {} protected override void OnValueChanged(EventArgs eventargs) { base.OnValueChanged(eventargs); valueChanged = true; EditingControlDataGridView.NotifyCurrentCellDirty(true); } protected virtual void NotifyDataGridViewOfValueChange() { valueChanged = true; if (this.dataGridView != null) { dataGridView.NotifyCurrentCellDirty(true); } }

42

Gregorics Tibor

Adattbla karbantarts

s vgl az interfsz implementlsa miatt megadand tulajdonsgok.

public object EditingControlFormattedValue { get{return this.Value.ToString();} set{this.Value = (int) value; } } public object GetEditingControlFormattedValue( DataGridViewDataErrorContexts context) { return EditingControlFormattedValue; } public void ApplyCellStyleToEditingControl( DataGridViewCellStyle dataGridViewCellStyle) {} public int EditingControlRowIndex { get{return rowIndex; } set{rowIndex = value; } } public bool EditingControlWantsInputKey( Keys key, bool dataGridViewWantsInputKey) { return false; } public void PrepareEditingControlForEdit (bool selectAll) {} public bool RepositionEditingControlOnValueChange { get{return false; } } public DataGridView EditingControlDataGridView { get{return dataGridView; } set{dataGridView = value; } } public bool EditingControlValueChanged { get{ return valueChanged; } set{ valueChanged = value; } } public Cursor EditingPanelCursor { get{ return base.Cursor; } } }

43

Gregorics Tibor

Adattbla karbantarts

3. Adatrcs oszloptpusnak megvltoztatsa Utols lpsknt trjnk vissza az els projektnkhz, s adjuk ennek a referenciihoz a DataGridViewFeaturesColumn projektet. Ezutn az rlapra feltett adatrcs oszlopainak szerkesztsnl (Tervez nzetben az adatrcs kijellse utn annak jobb fels sarkn megjelen SmartTag-gel) vlasszuk ki a features oszlopot, majd annak ColumnType tulajdonsghoz jelljk meg az ott felnyl ablakban mr lthat DataGridViewFeaturesColumn oszlop tpust. Adjuk a features adatrcs-oszlop objektumnak a dataGridViewFeaturesColumn nevet. Az rlap konstruktorban paramterezzk fel a features adatrcs-oszlopot. Sajnos e nlkl kezeletlen kivtelt dob a programunk.

public BuildingUpdateForm() { InitializeComponent(); object[] list = { "parking site", "garden", "swimming pool", "beach service" }; dataGridViewFeaturesColumn.List = list; }

rdemes az adatrcs szerkesztsi md tulajdonsgt tlltani: EditMode : EditOnEnter

Megjegyezzk, hogy az itt bemutatott vltozat knyelmes s tetszets hasznlathoz mg nhny mdostst vgre kellene hajtani. Pldul nem szp, hogy a cella passzv llapotban az adatbzisban trolt egsz szmot mutatja. gy read only zemmdban nem lehet megtekinteni a tnylegesen bejellt jellemzket, csak a bejells kdjt. Ezt a kvetkez fejezetben orvosoljuk majd.

44

Gregorics Tibor

Adattbla karbantarts

3. Hibaellenrzs A hibaellenrzs alapvet elve az, hogy a keletkez hibt annak keletkezsi helyhez s idejhez minl kzelebb fedezzk fel. Egy adattbla karbantartst vgz modulban, amikor az adattblt az adatbzisbl a memriba msoljuk, a hiba ellenrzst tbb szinten kell vgezni. 1. Mez szint: egy sor egy mezjnek helyessgt nmagban, a sor illetve a tbla tbbi adattl fggetlenl vizsgljuk. 2. Sor szint: egy sor mezinek kapcsolatt ellenrizzk. 3. Tbla szint: A szerkesztett sornak s a tbla tbbi sornak kapcsolatt ellenrizzk. 4. Adatbzis szint: A szerkesztett sort sszevetjk az adatbzis tbbi tbljval. Ezt tbbnyire nem soronknt vgezzk el, hanem akkor, amikor a tblt visszamentjk az adatbzisba. rtelemszeren ilyenkor az ellenrzs az adatbzis oldalon trtnik. (Kivtelt kpezhetnek az idegenkulcs-ellenrzsek, melyek rdemes a mez szint ellenrzs alatt gy megoldani, ahogy ezt a city_id illetve a shore_id esetben tettk, azaz eleve kizrjuk a hibzs lehetsgt.) Megjegyezzk, hogy ha az els hrom szinten az adatbzisbeli megszortsoktl eltr mdon vgznk hibaellenrzst, akkor szmos hiba csak a 4. szinten jelentkezik. A felfedett hibrl valamilyen formban mindig tjkoztatni kell a felhasznlt, s ki kell knyszerteni a hiba kijavtst. vakodjunk azonban attl, hogy alkalmazsunk tl erszakos, ennl fogva felhasznl ellenes legyen. Pldul nem kell ahhoz ragaszkodni, hogy a felhasznl azonnal helyes adatokat vigyen fel egy sor szerkesztse sorn, elg, ha a sor szerkesztsnek befejezsekor ellenrizzk a mezket. Mezellenrzs A hibaellenrzs legals szintje az egy egysgknt bevitt vagy szerkesztett adatok nll vizsglata. Itt ellenrizzk, hogy egy mez (cella, oszlop) rtke megfelel tpus-e (szm, karakterlnc, dtum, stb.), megfelel-e a formja (pl. telefonszm forma, EHA-kd forma), megadott tartomnyba esik-e (pl. 1 s 10 kztti egsz szm), s idegenkulcs esetn ltez elemre hivatkozik-e. (Ez utbbi kilg a tbbi ellenrzs kzl, hiszen eldntshez egy msik tblt kell vizsglni.) A helyes mez biztostsnak legegyszerbb mdja az, amikor olyan felletet alaktunk ki, amelyen keresztl nem lehet hibs adatot bevinni. Ezt alkalmaztuk a builing_id elrejtsnl s automatikus generlsnl, vagy a city_id, shore_id s features megadsnl. Szmos olyan vezrlt (NumericUpDown, DataTimePicker, MaskedTextBox) tallunk, amelyekkel a features mez kitltsnl bemutatott technikhoz hasonlan csak helyes adatokat lehet megadni. Ha ezt mgsem tudjuk biztostani, akkor hibaellenrz metdust kell rni. Adatrcsbeli adatszerkeszts esetn ezt a metdust clszer az adatrcs CellValidating esemnyhez deleglni. Ez az esemny akkor kvetkezik be, amikor a cellt ppen el akarjuk hagyni. (Ne tvesszk ssze a CellValidated esemnnyel, amely mr csak a cella elhagysa utn kvetkezik be.) Mivel mindegyik cella esetben ugyanaz a CellValidating esemny vltdik ki, erre kzs hibakezel metdust kell rni.

45

Gregorics Tibor

Adattbla karbantarts

private void buildingDataGridView_CellValidating(object sender, DataGridViewCellValidatingEventArgs e) { DataGridViewRow row = buildingDataGridView.Rows[e.RowIndex]; row.ErrorText = "" ; string colname = buildingDataGridView.Columns[e.ColumnIndex] .DataPropertyName; int n; if ((colname == "sea_distance" ) && !(int.TryParse(e.FormattedValue.ToString(),out n)&& n>0)) { row.ErrorText ="Sea_distance must be positive integer!" ; e.Cancel = true; } }

A hibaellenrzs egy sokg elgazs, ahol az egyes gak, az aktulis sor egyes oszlopaihoz tartoz cellartkeket ellenrzik Az e.ColumnIndex megmutatja, hogy ppen melyik oszlophoz tartoz cellartket kell ellenrizni, azaz melyik gra kerljn a vezrls. Az ellenrizend rtket az e.FormattedValue-ban talljuk. Ha az rtk hibs, akkor az e.Cancel = true rtkadssal tudjuk a felhasznlt visszaknyszerteni az ppen vizsglt cellba. A hiba kirsnak egy egyszer mdja az aktulis sor hibazenetnek hasznlata. (Ugyanezt hasznljuk a sor szint ellenrzsnl is.) Az aktulis sort az e.RowIndex segtsgvel kapjuk meg. Ha ennek Errors tulajdonsga az res sztringet tartalmazza, akkor nincs hibazenet. Ellenkez esetben egy gynevezett hiba ikon (alap esetben piros korongban egy felkiltjel) utal a hibra, a kurzort az ikonra mozgatva egy felbukkan dobozban megjelenik az Errors tulajdonsgban trolt hibazenet. Ha nem adatrcsban, hanem kln-kln vezrlkben szerkesztjk az adattbla aktulis sort (erre lttunk pldt az 1. Durva vltozat testre szabs nlkl c. fejezet vgn), akkor a vezrlk Validating esemnyhez kell deleglnunk esemnykezelt. Itt is lehet kzs esemnykezelt rni, amelynek els paramtere az esemnyt kivlt vezrl objektum lesz, ami alapjn beazonosthat, hogy mely rtket kell ellenriznnk. Az e.Cancel = true rtkads knyszerti vissza itt is a felhasznlt a hibt okoz vezrlhz. A hibazenet kijelzsre elegns eszkz az ErrorProvider. Ez egy specilis objektum, amit a Tervez nzetben a ToolBox-bl tudunk az alkalmazsunk rlapjhoz hozzadni. Ennek az objektumnak a SetError() metdusval jelezhetjk a hibt. A metdus els paramterben megadhatjuk azt a vezrlt, amelyben a hiba keletkezett, msodik paramtere pedig a hibazenet. Ha az zenet nem res sztring, akkor a jelzett vezrl mellett megjelenik egy hiba ikon, s ha arra lltjuk a kurzort, egy felbukkan dobozban a hibazenet olvashat. Kikapcsolni gy lehet a hibajelzst, ha a SetError() metdus hibazenet paramternek az res sztringet adjuk.

46

Gregorics Tibor

Adattbla karbantarts

Sorellenrzs A building tbla esetben nincs a mezk kztt olyan kapcsolat, amelyet ellenrizni kellene. Ugyanakkor a sorellenrzs keretben meg lehet vizsglni azt, hogy azok a mezk, amelyek nem tartalmazhatnak null rtket, ki lettek-e tltve. Ez lnyegt tekintve mezellenrzsi eset, de itt clszer vizsglni, hogy amg a felhasznl az aktulis sor mezi kztt lpked, ne bosszantsuk feleslegesen a kitltetlensgre vonatkoz hibazenetekkel. Adatrcs esetn a RowValidating kivtelkezel a sorellenrzs helye. Az adatkapcsolati objektum EndEdit() metdusa minden fggben lev mdostst elkld az adatforrsnak, esetnkben az adathalmazbeli building adattblnak. Ha egy olyan mez rtke null, amit az adattbla nem enged meg, akkor kivltdik a NoNullAllowedException kivtel.

private void buildingDataGridView_RowValidating(object sender, DataGridViewCellCancelEventArgs e){ DataGridViewRow row = buildingDataGridView.Rows[e.RowIndex]; row.ErrorText = ""; try{ this.buildingBindingSource.EndEdit(); }catch (NoNullAllowedException ex) { row.ErrorText = ex.Message.Substring(0,15) + " must be filled in"; e.Cancel = true; } }

Amennyiben kln vezrlkkel szerkesztjk a sort, akkor a szerkeszts befejezst jelz nyomgomb Click esemnyhez rendelt hibaellenrzst hasznljuk. Tblaellenrzs Megfelel mez s sorellenrzs mellett kiszrhetek az olyan, valjban tbla szint hibk, mint pldul az egyedi oszloprtk megsrtse vagy egy idegenkulcs tulajdonsgot srt mez rtk. Ha ezt nem tettk volna meg, akkor a DataError esemny vltdik ki. (A kapcsolati objektum is, s az adatrcs is rendelkezik DataError hibaesemnnyel.) Adatbzis ellenrzs Ha elg figyelmesek voltunk, s az adatbzis minden megszortst figyelembe vettk, a tbla visszamentskor mg mindig bekvetezhetnek hibk, kezdve attl, hogy nem nyithat meg a korbban mr felptett kapcsolat, egszen addig, hogy egy tbb felhasznls alkalmazs estn az ltalunk mdostott adatokat kzben ms felhasznl is mdostotta. Ilyenkor a legkevesebb, hogy ezekrl a hibajelensgekrl tjkoztassuk a felhasznlt, amelyhez a visszamentsnl az SqlException kivtelt kell lekezelni.

47

Gregorics Tibor

sszetett megjelentsek

sszetett megjelentsek
SSZETETT MEGJELENTSEK ........................................................................................ 48
1. MEZK EGYEDI LTVNNYAL ....................................................................................................................... 50

Ellenrz dobozos oszlop ................................................................................................. 50 Napok neveit megjelent oszlop ...................................................................................... 50 Egyedi vezrlvel elltott oszlop ...................................................................................... 52
2. SZMTOTT MEZK ....................................................................................................................................... 54

Szmtott mez sajt sor alapjn...................................................................................... 54 Szmtott mez szltbla alapjn ................................................................................... 55 Szmtott mez gyermektbla alapjn.............................................................................. 56 Szmtott mez sajt tbla alapjn................................................................................... 56
3. KAPCSOLT TBLA S KARBANTARTSA ........................................................................................................ 57

Gyermektbla megjelentse ............................................................................................ 57 Gyermektbla karbantartsa............................................................................................ 57 Dinamikusan vltoz listj kombinltdoboz .................................................................. 58
4. SZRS .......................................................................................................................................................... 62

Szrs belltsnak helye ............................................................................................... 62 sszetett szrst bellt egyedi vezrl .......................................................................... 62 Egy adatbzis egymssal sszefgg adattblkbl ll. Ezrt egy adattblnak akr nzegets, akr mdosts cljbl trtn megjelentsnl a vele kapcsolatban ll ms tblkban trolt adatok is szerepet jtszanak. Egy adattbla sszetett megjelentsn azt rtjk, amikor nemcsak a tblban trolt adatokat tesszk ki a felhasznli felletre, hanem az ezekkel az adatokkal kapcsolatos ms adatokat is. Ezt tettk mr az elz fejezetben is, amikor idegenkulcs megjelentse helyett, az azzal azonostott msik tblban trolt jelentst mutattuk meg a felhasznli felleten. De ide sorolhat az plet jellemzinek ellenrzdoboz-lists egyedi megjelentse is. Az sszetett megjelents tovbbi lehetsge, hogy olyan, gynevezett szmtott oszlopokat is kirhatunk, amelyek kzvetlenl nem szerepelnek az adatbzisban. Ezek rtkt az aktulis tbla, illetve az azzal kapcsolatban ll ms tblk alapjn szmthatjuk ki. Elfordulhat az is, hogy szl-gyermek kapcsolatban ll tblkat egyszerre kell megmutatnunk, de a gyermektblnak csak azon sorait, amelyek a szltbla aktulis sorhoz vannak rendelve. A feladatokat egy kpzelt utazsi iroda apartman-foglalsi tevkenysghez hasznlt Apartments adatbzisra fogalmazzuk meg. Ebben a fejezetben ennek az adatbzisnak szmos tbljval dolgozni fogunk, amelyek kztt a kzpontban az apartment nev tbla fog llni.
CREATE TABLE apartment ( apartment_id INTEGER PRIMARY KEY, building_id INTEGER NOT NULL, number VARCHAR(10), floor TINYINT, room VARCHAR(30) NOT NULL, bed TINYINT, spare_bed TINYINT, turnday TINYINT, features INTEGER, renovation INTEGER comment VARCHAR(100),

48

Gregorics Tibor

sszetett megjelentsek

FOREIGN KEY (building_id) REFERENCES building ); CREATE TABLE price ( apartment_id INTEGER PRIMARY KEY, season_id INTEGER PRIMARY KEY, price INTEGER, FOREIGN KEY (apartment_id) REFERENCES apartment, FOREIGN KEY (season_id) REFERENCES season ); CREATE TABLE season ( season_id INTEGER PRIMARY KEY, name VARCHAR(30) start_date DATETIME, end_date DATETIME, ); CREATE TABLE building ( building_id INTEGER PRIMARY KEY, name VARCHAR(30), city_id INTEGER NOT NULL, street VARCHAR(30) NOT NULL, sea_distance INTEGER, shore_id INTEGER, features INTEGER, comment VARCHAR(100), FOREIGN KEY (city_id) REFERENCES city, FOREIGN KEY (shore_id) REFERENCES shore ); CREATE TABLE city ( city_id INTEGER PRIMARY KEY, name VARCHAR(30) );

Tzzk ki a megoldand feladatot: Feladat: Ksztsnk olyan grafikus fellet alkalmazst, amely lehetsget ad az apartmanok megjelentsre s egy apartmannak a klnbz szezonokban megllaptott brleti djainak megadsra! Elszr az apartment adattbla megjelentsvel foglalkozunk. Elrejtjk a felhasznl ell a tblban trolt bels azonostkat (ehhez, ha kell, egyedi cella formt definilunk), de megjelentjk az olyan fontos kapcsold adatokat, mint az apartmannak a building tblbl kiolvashat neve s cme, az apartment tbla aktulis sorbl kiszmthat gy/szoba arny, az apartmannal egy pletben lev apartmanok szma, s az apartman (price gyermek tblbl kiszmthat) tlag ra. Ezutn az apartment tblhoz kapcsold price tbla megjelentst s karbantartst biztost felletet alaktjuk ki, de gy, hogy a price tblnak csak azokat a sorait mutatjuk meg, amelyek az ppen kijellt apartmanhoz kapcsoldnak. Ahogy az apartmanokat mutat felleten megvltoztatjuk a kijellt apartmant, gy fog vltozni az rlistt mutat nzet. A tovbbiakban tbb olyan mveletsort vgznk, amelyet az elz fejezetben mr rszletesen megtrgyaltunk. Ezrt ezekre itt kisebb figyelmet szentelnk. 49

Gregorics Tibor

sszetett megjelentsek

1. Mezk egyedi ltvnnyal Hozzunk ltre egy Windows Application alkalmazst! Rendeljnk hozz adatforrst, amelybe beemeljk az apartments adatbzis fent felsorolt adattblit. Legyen az gy ltrejtt adathalmaz neve: priceDataset. (Ne felejtsk el mg ezeltt az adatbzisban az sszes tblakapcsolatot definilni s elmenteni.) Hzzuk r (drag&drop) az adatforrsbl az rlapra az apartment tblt, amely ltal ltrejn egy adatrcs, egy navigtor, egy adathalmaz, egy adapter s egy adatkapcsolati objektum. Vegyk le az adatrcsbl az apartment_id-t s a building_id-t, gondoskodjunk a turnday, features s renovation oszlopok dekdolt megjelentsrl. lltsuk t az EditMode tulajdonsgot EditOnEnter-re. Vgl legyen az adatrcs ReadOnly s trljk a navigtorsv ments nyomgombja (apartmentBindingNavigatorSaveItem) Click esemnykezeljnek trzst, hiszen a jelen alkalmazsnak nem feladata az apartmanok mdostsa. Ezzel kt legyet is tttnk egy csapsra: nem kell az apartment_id automatikus generlsrl gondoskodni, s nincs szksg az jonnan bevitt adatok hibaellenrzsre. Ellenrz dobozos oszlop Jelentsk meg az igaz/hamis rtk renovation mezt egy ellenrz doboz segtsgvel! A renovation mez az apartman azon tulajdonsgt mutatja, hogy az hasznlhat-e ppen, nincs-e feljts alatt. A renovation oszlop ColumnType tulajdonsgt a gyri DataGridViewCheckBoxColumn tpusra lltsuk be. Ezt a tervez nzetben az adatrcs kijellse utn annak jobb fels sarkn megjelen SmartTag-gel felnyitott ablak EditColumn menpontjnl megjelen oszlopszerkesztvel tehetjk meg legegyszerbben. Napok neveit megjelent oszlop A turnday mez a ht egyik napjnak sorszmt trolja. Jelentsk meg ezt a megfelel nap nevvel! Az apartmanok csak teljes hetekre brelhetk, s minden apartmannl rgztett, hogy a brlet a ht melyik napjn kezddik. A turnday mez a ht ezen napjnak sorszmt tartalmazza, amely helyett a megfelel nap nevt szeretnnk megmutatni. Ez a helyzet nem nagyon klnbzik attl az esettl, amikor a building tbla karbantartsnl a city_id helyett a telepls nevet kellett megjelenteni. Az egyetlen eltrs az, hogy a ht napjai nincsenek az adatbzis egy kln tbljban felsorolva. Egy adatrcsbeli oszlop adatforrsa azonban nemcsak egy adatbzisbeli tbla lehet, hanem brmi: esetnkben a ht napjait felsorol gyjtemny, pldul egy tmb. Persze ebben a napokat a sorszmukkal egytt kell felsorolni, hiszen a napok sorszma a klnbz nyelvi kultrkban eltrhet. (Magyarorszgon a ht els napja a htf, de Angliban a napok felsorolsa a vasrnappal kezddik.) A .NET alatt az aktulis nyelvi kultrt knnyen be tudjuk pteni a programunkba. A Thread.CurrentThread.CurrentCulture = new CultureInfo("en-GB"); utastssal (a Thread a Systems.Threading nvtrben tallhat) a brit-angol nyelvi kultrt llthatjuk be. Ezutn a napok angol neveit a
Thread.CurrentThread.CurrentCulture.DateTimeFormat.DayNames

gyjtemnybl tudjuk kiolvasni. Elsknt definilunk a projektnkben egy Day osztlyt, amely a ht egy napjnak tpust rja meg. Ennek kt tulajdonsga van: a nap neve illetve a nap sorszma. 50

Gregorics Tibor

sszetett megjelentsek

public class Day { private byte dayNumber; public byte DayNumber { get { return dayNumber; } set { dayNumber = value; } } private string dayName; public string DayName { get { return dayName; } set { dayName = value; } } public Day(string name, byte n) { dayName = name; dayNumber = n; } }

Msodszor a Data Sources nzetben egy j adatforrst ksztnk a varzslval. Az adatforrs alapja most egy Day tpus objektum (object) lesz, nem adatbzis. Kijelljk a projektnk Day osztlyt (ez csak azt kveten ltszik a varzslban, ha mr jrafordtottuk a projektet). Harmadik lpsben az apartment tblt mutat adatrcshoz szerkesztjk hozz (SmartTag / Edit column) a turnday oszlopot. ColumnType: DataGridViewComboBoxColumn DataSource: Other Data Sources/ Project Data Sources/ price/ Day DisplayMember: DayName ValueMember: DayNumber DisplayStyle: Nothing Megjegyezzk, hogy most tbbet is tettnk a kelletnl, hiszen ha ennek az oszlopnak nem lenne igaz a ReadOnly tulajdonsga, akkor az oszlop mezben egy kombinlt doboz segtsgvel lehetne kivlasztani a megfelel napot. Htra van mg, hogy a most ltrejtt dayBindingSource objektum DataSource tulajdonsghoz hozzrendeljk a ht napjait tartalmaz gyjtemnyt. Legyen ez a week tmb, amelyet az rlapunk osztlynak adatagjaknt definilunk, s a konstruktorban tltjk fel a megfelel sorszmozssal egytt.

51

Gregorics Tibor

sszetett megjelentsek

using System.Globalization; using System.Threading; public partial class PriceViewForm : Form { public Day[] week = new Day[8]; public PriceViewForm() { InitializeComponent(); ... week[0] = new Day("none", 0); byte n = 0; Thread.CurrentThread.CurrentCulture = new CultureInfo("en-GB"); foreach (string dayname in Thread.CurrentThread. CurrentCulture.DateTimeFormat.DayNames) { week[n] = new Day(dayname, n); ++n; } dayBindingSource.DataSource = week; } ...

Egyedi vezrlvel elltott oszlop A features mezben trolt kd helyett azon tulajdonsgok ellenrz dobozos listjt jelentsk meg, amelyek egy apartman tulajdonsgait alkotjk: kilts, terasz, lgkondicionls! A features oszlop tpusnak belltsa pont ugyangy trtnik, ahogy ezt korbban, a building tbla features oszlopval tettk. Felhasznlhatjuk az ott nll projekt keretben elksztett DataGridViewFeaturesColumn oszloptpust. (Mg az sem kell, hogy az a project a mostani solution rsze legyen, elg a megfelel dll kiterjeszts fjlt a mostani projektnk hivatkozsai kz felvennnk.) jrafordts utn az adatrcs oszlopszerkesztjnek segtsgvel belltjuk a features oszlop ColumnType tulajdonsgt az ott felnyl ablak ltal most mr felknlt DataGridViewFeaturesColumn tpusra. Vgl adjuk a features adatrcs-oszlopnak a dataGridViewFeaturesColumn nevet. Egyetlen problma addik csak, nevezetesen, hogy mi mdon akadlyozzuk meg, hogy a features mezben felsorolt elemek kijellst meg tudja vltoztatni a felhasznl. Ha az oszlop ReadOnly tulajdonsgt lltjuk igazra, akkor a cellkban felsorolt elemeket sem tudjuk vgiggrgetni. E helyett egy igen egyszer megoldst knl az, ha a features mez vezrlje egy CheckedListBox tpus vezrlbl szrmazik, amelyik rendelkezik egy gynevezett SelectionMode tulajdonsggal. Ha ezt None-ra lltjuk, akkor a vezrl csak olvashat lesz. Ehhez egyrszt fel kell venni a DataGridViewFeaturesColumn osztlyba egy publikus SelectionMode tpus tagot (public SelectionMode selectionmode), msrszt gondoskodni kell arrl, hogy a DataGridViewFeaturesCell osztly InitializeEditingControl() metdusa (lsd korbban) tadja ezt az informcit az egyedi vezrlnknek. Ehhez egyetlen rtkadst kell beilleszteni a korbbi kdba. 52

Gregorics Tibor

sszetett megjelentsek

public override void InitializeEditingControl(...) { base.InitializeEditingControl(...); FeaturesEditingControl ctl = DataGridView.EditingControl as FeaturesEditingControl; DataGridViewFeaturesColumn fc; ... fc = this.OwningColumn as DataGridViewFeaturesColumn; ctl.SelectionMode = fc.SelectionMode; ctl.List = fc.List; ctl.Value = (this.Value == null || this.Value.ToString() == "") ? 0 : (int)this.Value; } }

Az jonnan bevezetett tulajdonsgot bellthatjuk az alkalmazsunk rlapjnak konstruktorban ott, ahol a vezrlben megjelentett sszetevk listjt is megadjuk. (A lista megadsa nlkl kezeletlen kivtelt dob a programunk.)
object[] list = { "looking sea", "looking green", "terrace", "air condition" }; dataGridViewFeaturesColumn.List = list; dataGridViewFeaturesColumn.SelectionMode = SelectionMode.None;

Htra van mg egy, az elz fejezetbl maradt adssg trlesztse. Ez az egyedi oszloptpus egyelre olyan, hogy amikor egy cella nem aktv, akkor nem az ellenrzdoboz-lists formban jelenik meg, hanem azt a szmkdot mutatja, amely tnylegesen az adatbzisban trolva van. Ez nem j, ltalnos cl, hogy a bels kdokat nem mutatjuk a felhasznl fel. Az egyedi vezrlvel elltott oszlopok esetn a megjelenst a DataGridViewCell osztly szintjn, esetnkben az abbl szrmaztatott DataGridViewFeaturesCell osztly Paint() metdusban tudjuk szablyozni. Ez egy felldefinilt metdus.
protected override void Paint( Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, int rowIndex, DataGridViewElementStates cellState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts) { base.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts); Rectangle newRect = new Rectangle( cellBounds.X + 1, cellBounds.Y + 1, cellBounds.Width - 4, cellBounds.Height-4); graphics.FillRectangle(Brushes.LightGray, newRect); graphics.DrawString("click here", new Font("Arial", 8), Brushes.Black, newRect); }

53

Gregorics Tibor

sszetett megjelentsek

A metdus meghvja az sosztly Paint() metdust, majd megtervezi a passzv cellk ltvnyt. Ebben az esetben ez egy egyszer fedtglalap a click here felirattal. Nyilvn ennl gyesebb megjelenst is lehetne tervezni. Semmi akadlya pldul az aktulisan kivlasztott jellemzket (azok rvidtseit) felsorolni. Hozzfrhetnk a jellemezk teljes listjhoz (az InitializeEditingControl-ban ltott mdon), a kivlasztst kdol szmhoz (value paramter), melynek dekdolst a FeaturesSelectingControl osztly Decoding() metdushoz hasonl mdon elvgezhetjk. 2. Szmtott mezk Szmtott meznek egy tbla azon oszlopait nevezzk, amelyek az eredeti tblban nincsenek jelen, rtkket valamilyen mdon, tbbnyire ms adatbzisbeli rtkek alapjn szmolhatjuk, s ezrt termszetesen nem lehet ket kzvetlenl mdostani. Annak megfelelen, hogy egy szmtott mez rtknek ellltshoz milyen ms adatokra van szksg, klnfle eseteket klnbztethetnk meg. Mieltt ezen eseteket megvizsglnnk, mdostsuk az rlap Load esemnyekor lefut esemnykezelt. Ez jelenleg az apartment tbla betltst vgzi, de neknk a tbbi tblt is be kell tlteni az adathalmazba. Hozzuk ltre a building, city, price s season tblk kezelshez alkalmas adapter objektumokat (ezeket a ToolBox segtsgvel pldnyosthatjuk), s rjuk bele a Load esemnykezeljbe ezen tblk betltst vgz metdushvsokat.
private void Form1_Load(object sender, EventArgs e) { apartmentTableAdapter.Fill(apartmentsDataSet.apartment); priceTableAdapter1.Fill(apartmentsDataSet.price); buildingTableAdapter1.Fill(apartmentsDataSet.building); cityTableAdapter1.Fill(apartmentsDataSet.city); seasonTableAdapter1.Fill(apartmentsDataSet.season); }

Szmtott mez sajt sor alapjn Egsztsk ki az apartment tbla megjelentst egy olyan mezvel, amely az apartmanbeli gy/szoba arnyt (rta) mutatja! A szmtott mezt a memriban trolt apartment adattblhoz j oszlopknt vegyk hozz. Tekintsk az adatllomny tervezi nzett (priceDataSet.xsd). Kattintsunk az apartment tblra a jobb egrfllel, s a felnyl ablakok segtsgvel adjunk egy j oszlopot a tblhoz. Ennek tulajdonsgait az albbiak szerint lltsuk be. Name: rate Caption: rate Expression: bed/room DataType: System.Double ReadOnly: true A szmtott rteket definil kifejezs az apartment tbla aktulis sora bed s room mezinek rtkeire hivatkozik. Ezt kveten az apartmanokat mutat adatrcs oszlopaihoz is vegyk hozz az j mezt. Az oszlopszerkeszt ilyenkor mr ltja ezt, s fel is knlja a hozzvehet oszlopok kztt. 54

Gregorics Tibor

sszetett megjelentsek

Szmtott mez szltbla alapjn Egsztsk ki az apartment tbla megjelentst olyan mezkkel, amely az apartmant tartalmaz plet tulajdonsgait, mondjuk a building tblbl kiolvashat nevet, telepls s utca nevet mutatja! Ebben az esetben lnyeges szerep jut a building tbla s az apartment tbla kztti szlgyerek kapcsolatnak. Az apartment tbla building_id mezje idegenkulcs a building tblra nzve. Minden apartman pontosan egy plethez tartozik. Ezt a kapcsolatot az adatbzisban FK_apartment_building nven jegyeztk be. Adjunk j oszlopokat az (priceDataSet.xsd) hasznlva. apartment tblhoz az adatllomny tervezi nzett

Az plet nevnek, mint szmtott meznek az rteke a building tblban ( a szl tbla) tallhat, annak a name mezjben. Ezt, amikor a building az egyedli szl tbla, a parent.name hivatkozs definilja. Tbb szl tbla esetn a parent(FK_apartment_building).name kifejezst kell hasznlnunk. Teljesen hasonl mdon jrjunk el az plet utcanevnek szmtott mezknt val felvtelnl. (Mindkt mez automatikusan ReadOnly tulajdonsg lesz.) Table: Name: Expression: apartment name parent.name Table: Name: Expression: apartment street parent.street

Bonyolultabb a helyzet a telepls nevnek megjelentsnl. Erre egy kt lpsbl ll technikt mutatunk. Elszr szmtott mezt hozunk ltre a building tblban, majd erre az j szmtott mezre hivatkoz msik szmtott mezt az apartment tblban. Table: building Name: city Expression: parent(FK_building_city).name Table: apartment Name: city Expression: parent.city

Vgl gondoskodunk az apartment tbla j szmtott mezinek az adatrcsban val megjelentetsrl. (Megjegyezzk, hogy amikor a building tbla karbantartsnal a city_id-ek helyett a megfelel telepls neveket mutattuk meg az adatrcsban, akkor hatsban ugyanazt rtk el, mintha kln szmtott mezt definiltunk volna a teleplsneveknek, s az adatrcsban csak ezt, a city_id-t pedig nem jelentettk volna meg. Csak a teljessg ignye miatt emltjk meg azt is, hogy fogalmilag ebbe a pontba sorolhat az olyan eset is, amikor egy mez szmtott rtkt nem egy msik tblbl, hanem egy tetszleges gyjtemny alapjn szmoljuk ki. Erre a legjobb plda az elz fejezetben szerkesztett turnday mez, amelynek htterben a week objektum ll. Itt is igaz akrcsak a building_id esetben , hogy eredetileg egy bels azonostt tartalmaz meznk volt, amely helyett annak jelentst jelentettk meg, amelyet a week gyjtemnybl szmolhattunk ki.) 55

Gregorics Tibor

sszetett megjelentsek

Szmtott mez gyermektbla alapjn Egsztsk ki az apartment tbla megjelentst egy olyan mezvel, amely az apartman tlagos brleti djt mutatja! Ez a price tbla segtsgvel szmolhat, amely az apartman egy htre szl brleti djait tartalmazza a klnbz szezonokban. A price tbla gyermektblja az apartment tblnak. Kapcsolatukat az FK_price_apartment nv azonostja. Most a price az egyetlen gyermektblja az apartment-nek, ezrt a child(FK_price_apartment) hivatkozs helyett hasznlhatjuk az egyszerbb child-ot. Minden price-beli sor valamelyik apartmanhoz tartozik, s egy apartmannak a klnbz szezonokban krt brleti djait tartalmazza. Ezen djak tlagt szeretnnk kiszmtani. Ehhez hasznlhat az Avr() aggregcis fggvny. Elszr az apartment tbla j szmtott mezjt definiljuk az eddig ltott mdon. Table: apartment Name: average fee Expression: Avg(child.price) Utna felvesszk ezt a mezt az adatrcs oszlopai kz. Szmtott mez sajt tbla alapjn Egsztsk ki az apartment tbla megjelentst egy olyan mezvel, amely az apartmannal egy pletben lev apartmanok sszes szmt mutatja! gy tnhet, hogy ez egyszerbb eset, mint az elz kett, hiszen nem ignyli a kapcsolt tblk vizsglatt. Ha azonban nem akarunk az eddigieken kvl ms eszkzket hasznlni, akkor a Count() fggvny korltai miatt az albbi krlmnyesebb utat kell vlasztanunk. Elszr a building tblnl hozzuk ltre az itt ignyelt szmtott mezt, Table: building Name: count Expression: Count(child.building_id) majd ezt a mezt az apartment tblba msoljuk Table: apartment Name: neighbour Expression: parent.count Ezt kveten az adatrcs oszlopaihoz is vegyk hozz ezt a neighbour mezt.

56

Gregorics Tibor

sszetett megjelentsek

3. Kapcsolt tbla s karbantartsa Most azt mutatjuk meg, hogy kapcsolt tblk esetn hogyan lehet olyan nzetet ltrehozni, amelyben egy tbla a gyermek tbljval egytt jelenik meg az rlapon (a gyermek tblban mindig a f tbla aktulis sorhoz kapcsold sorokat ltszdnak), s hogyan mdosthatak a gyermek tbla adatait.1 Gyermektbla megjelentse Jelentsk meg az apartment tbla mellett az ahhoz tartoz brleti djakat szezononknt elklntve! Vltsunk t az alkalmazs rlapjt mutat tervez nzetbe! Az ehhez rendelt adatforrsban keressk meg a price tblt. Vigyzat! Az adatforrsban tbb helyen is tallkozhatunk a price tblval. nllan is, de az apartment tblnak alrendelve is. Ez utbbi nem a teljes price tblt, hanem annak csak azt nzett szimbolizlja, amely az aktulis apartmanhoz tartoz price tblabeli sorokat mutatja. A price tblnak ezt a szrst a varzsl automatikusan belltja. Hzzuk be az rlapra az apartment tblnak alrendelt price tblt! (Felttelezzk, hogy az apartment tbla adatrcsa az elz fejezetek mdostsain tesve mr ott van.) Ekkor megjelenik egy jabb adatrcs (megfelel adapter objektum s adatkapcsolati objektum ksretben), amely utn az alkalmazs fordthat, futtathat. Elszr vgezznk el nhny mdostst a price adatrcsn (ehhez hasonlkat mr korbban is csinltunk, gy ezek nem jelenthetnek gondot). Rejtsk el a price tbla adatrcsn a bels azonostkat mutat oszlopokat. Jelentsk meg a season_id helyett a szezon nevt. Ehhez hasznlhatunk egy kombinlt dobozknt megjelen mezt. Jelentsk meg a szezon idszakt is de gy, hogy vegyk figyelembe az apartman fordul napjt (turnday)! A szezon hatr ugyanis tbbnyire nem esik egybe az apartman fordulnapjval, ezrt az adott apartmant esetben a szezonhatrt a rkvetkez fordulnapra kell eltolni. Ehhez meg kell hatrozni, hogy a szezon hatr a ht melyik napjra esik (legyen ennek sorszma h), s ha a fordulnap sorszma f, akkor a szezonhatr dtumt (f+7-h)%7-tel kell megnvelni. Gyermektbla karbantartsa Jelenleg az apartment tblt nem akarjuk mdostani, ezrt az azt mutat adatrcs ReadOnly tulajdonsga igaz, tovbb kivettk a navigtorsv ments nyomgombjnak Click esemnykezelsbl az apartment tbla visszamentst is. Most helyezzk el a price tbla mentst vgz kdrszletet a navigtorsv ments nyomgombja Click esemnykezeljnek trzsben.

Nem trtnk ki a msik irnyra: a f tbla aktulis sorhoz tartoz szl tblabeli sorok megjelentsre. Ilyen lenne pldul az, amikor megjelentjk egy teleplsen tallhat sszes plet listjt. Ez ugyanis egy tipikus szrsi feladat, amellyel ksbb foglalkozunk.

57

Gregorics Tibor

sszetett megjelentsek

private void apartmentBindingNavigatorSaveItem_Click( object sender, EventArgs e) { this.Validate(); this.apartmentBindingSource.EndEdit(); this.priceTableAdapter.Update(apartmentsDataSet.price); }

Dinamikusan vltoz listj kombinltdoboz Vrtezzk fel hibaellenrzssel a price tbla adatrcsnak a szerkesztst gy, ahogyan ezt a building tbla karbantartsnl lttuk. Itt egy dologra kell figyelnnk. Egy apartmannl minden szezonhoz pontosan egy rat lehet nyilvntartani. A felvitelnl mg megengedhetjk azt, hogy bizonyos szezonok rai ne legyenek megadva, de azt nem, hogy ugyanarra a szezonra tbbfle r is legyen: az apartman s a szezon egy sszetett egyed kulcs a price tblban. Ennek ellenrzst elvgezhetjk a price tbla aktulis sornak rvnyestsekor (Validated), de az igazn elegns megolds az lenne, ha a szezon megadsakor felbukkan kombinlt doboz, soha nem ajnlana fel olyan szezon neveket, amelyeket az elz megszorts miatt gysem lehetne vlasztani. Zrjuk ki annak a lehetsgt, hogy egy apartman ugyanazon szezonjhoz egyszerre tbb rat is meg lehessen adni! Ezt a korltozst ott lehet rvnyesteni, amikor a price tbla jabb sorban a season mezt tltjk ki. Azt knny megoldanunk, hogy itt a valsgban nyilvntartott season azonostk helyett annak neve jelenjen meg. Ennek megvalstsval mr tbb esetben is tallkoztunk. ColumnType: DataSource: DisplayMember: ValueMember: DisplayStyle: DisplayStyleForCurrentCellOnly: DataGridViewComboBoxColumn seasonDataSources name season_id DropDownButton true

Az adatforrsnl szerepl seasonBindingSource objektumot gy hozzuk ltre, hogy a DataSource els belltsakor az Other Data Sources/ Project Data Sources/ priceDataSet/ season vlasztst adjuk meg. Ezzel a megoldssal a kombinltdobozban egyelre mindig az sszes szezon neve fog megjelenni. Most ezt kellene neknk megszrni gy, hogy csak azok a szezonok legyenek vlaszthatak, akik mg nem szerepelnek a price tbla adott apartmanhoz tartoz soraiban. A setCurrentFilter() metdus a seasonBindingSource objektum Filter tulajdonsgt lltja majd be a megfelel szrfelttelre, mg a szrs kikapcsolst egyszeren a seasonBindingSource = "" rtkadssal vgezzk el. A nehzsget az okozza, hogy amikor egy mez megfelel kitltse rdekben belltunk egy olyan szrfelttelt, amely kizrja az adott oszlopban mr szerepl szezonokat, akkor ez a szrs az egsz oszlopra fog vonatkozni. Ha az oszlop vagy valamelyik mr korbban kitlttt cellja jrarajzolsra kerl sor, akkor azok a mezk, ahov korbban mr szezon nevet rtunk, ress vlnak, hiszen a szrfelttel nem engedi az rtkk megjelentst. Ezrt a szrst csak akkor szabad bekapcsolni, mieltt az adott mez kitltst segt kombinlt doboz legrdl menlistja megjelenik, s a lista lezrsa utn a szrst azonnal ki kell kapcsolni. 58

Gregorics Tibor

sszetett megjelentsek

Tovbbi problma, hogy az aktulis cellnl alkalmazott szrs kizrja az aktulis cellba korbban bert nevet is. Ezrt minden alkalommal, amikor a szrst bekapcsoljuk a szr felttelt gyengteni kell, hogy az ne zrja ki az aktulis cella rtkt (ha van ilyen). Idkml megolds, ha eltroljuk azt a szr felttelt (base_filter), amely az sszes adott oszlopbeli nevet kiszri, s egy cella szrsnek belltsakor ezt gyengtjk az adott cella rtkvel. Az alapbelltst a setBaseFilter()metdus vgzi.
private string base_filter; private void setBaseFilter() { base_filter = ""; foreach (priceDataSet.priceRow row in priceDataSet.price) { base_filter += string.Format(" AND season_id<>'{0}' ", row.season_id); } if(base_filter!="") base_filter = base_filter.Substring(4); }

A base_filter-t elg egyrszt a price tbla betltsekor (priceForm_Load()) kiszmolni, msrszt, amikor a price tbla season oszlopnak valamelyik mezje mdosul (priceDataGridView_RowValidated()).
private void priceForm_Load(object sender, EventArgs e) { priceTableAdapter.Fill(this.priceDataSet.price); apartmentTableAdapter.Fill(this.priceDataSet.apartment); buildingTableAdapter.Fill(priceDataSet.building); cityTableAdapter.Fill(apartmentsDataSet.city); seasonTableAdapter.Fill(apartmentsDataSet.season); setBaseFilter(); } private void rentDataGridView_RowValidated( object sender, DataGridViewCellEventArgs e) { setBaseFilter(); }

A setCurrentFilter() metdust ktflekpen is meglehet hvni. Paramter nlkl, ilyenkor egyetlen feladata a seasonBindingSource.Filter rtkknek tadni a base_filter-t, vagy annak partnernek az azonostjval (ez egy egsz szm), amelyet ki akarunk venni a szrsbl.

59

Gregorics Tibor

sszetett megjelentsek

private void setCurrentFilter(params int[] current_id) { string filter = base_filter; if (filter != "" && current_id.Length > 0) filter += " OR "; if ( current_id.Length > 0 ) filter += string.Format(" season_id = '{0}' ", current_id[0]); seasonBindingSource.Filter = filter; }

Ezt a metdust mindig meg kell hvni, amikor egy szezonnv szerkesztshez felnyitjuk a kombinlt dobozt, illetve meg kell szntetni a szrst, amikor a kombinlt doboz lenyl menjt lezrjuk. Erre a legelegnsabb megolds a kombinlt doboz DropDown s DropDownClosed esemnyeinek kezelse lenne. Az els esetben az adott cella aktulis rtkvel (ez egy season azonost) meg kell hvni a setCurrentFilter()-t (ha nincs mg rtke a cellnak, akkor paramter nlkl), a msodik esetben a seasonBindingSource.Filter = "" rtkadsra van szksg. gyeljnk arra, hogy a szrs vltozsakor a kombinlt doboz listjban korbban kivlasztott sor megvltozik, ezrt azt ideiglenesen meg kell jegyezni s jra belltani.
private ComboBox seasonComboBox; private void seasonComboBox_DropDown(object sender, EventArgs e) { if (priceDataGridView.CurrentCell.Value == DBNull.Value) setCurrentFilter(); else{ int i = (int) seasonComboBox.SelectedValue; setCurrentFilter( (int)priceDataGridView.CurrentCell.Value); seasonComboBox.SelectedValue = i; } } private void seasonComboBox_DropDownClosed (object sender, EventArgs e) { int i = (int) seasonComboBox.SelectedValue; seasonBindingSource.Filter = ""; seasonComboBox.SelectedValue = i; priceDataGridView.Refresh(); }

E fenti kt esemnykezelt nem tudjuk a tervezvel hozzrendelni a megfelel esemnyekhez. A hozzrendels kdjt pldul a priceDataGridView adatrcs EditingControlShowing esemnynek kezeljbe helyezhetjk. Figyeljk meg, hogyan lehet beazonostani, hogy az adatrcs ppen melyik oszlopban llunk.

60

Gregorics Tibor

sszetett megjelentsek

private void priceDataGridView_EditingControlShowing( object sender, DataGridViewEditingControlShowingEventArgs e) { if (((DataGridView)sender).CurrentCell.OwningColumn. DataPropertyName == "season_id") { seasonComboBox = priceDataGridView.EditingControl as DataGridViewComboBoxEditingControl; seasonComboBox.DropDown += new EventHandler(seasonComboBox_DropDown); seasonComboBox.DropDownClosed += new EventHandler(seasonComboBox_DropDownClosed); } }

Vgl mg egy aprsg. Amikor a kombinlt doboz listja lenylik s tlnylik az adatrcs bels terletn, akkor az adatrcs jrarajzolja magt. Mivel ilyenkor be van kapcsolva a szr, az jrarajzols a tbbi sor season mezjben megjelentett neveket ideiglenesen trli. Ezt gy lehet megakadlyozni, hogy az jrarajzols eltti szrfelttelt elmentjk, a szrst kikapcsoljuk, majd az jrarajzols utn visszakapcsoljuk
private void priceDataGridView_RowsAdded( object sender, DataGridViewRowsAddedEventArgs e) { string filter = seasonBindingSource.Filter; seasonBindingSource.Filter = ""; priceDataGridView.Refresh(); seasonBindingSource.Filter = filter; }

61

Gregorics Tibor

sszetett megjelentsek

4. Szrs Szrsrl akkor beszlnk, amikor a felhasznli felleten a trolt adatainknak csak egy rszt mutatjuk meg. Egy adattbla szrsn az adattbla sorainak szrst rtjk. Ilyen szrsekkel mr eddig is tallkoztunk, pldul amikor a price tblnak csak apartment tblnak aktulisan kivlasztott sorhoz (egy adott apartmanhoz) tartoz sorait jelentettk meg egy adatrcsban (kapcsolt tbla megjelentse), vagy amikor az elbb bemutatott dinamikusan vltoz kombinlt doboz tartalmt lltottuk be. Szrs belltsnak helye Az adattbla szrst tbb ponton is meg lehet valstani. 1. Adatbzisbl val betltskor Az adatbzis egy tbljnak memriba tltsekor is lehet mr szrst alkalmazni, ha a betltst vezrl parancs (DataCommand) objektumban vagy az adapter (DataAdapter) objektum SelectCommand tulajdonsgban egy megfelel SQL SELECT lekrdezst vagy trolt eljrst adunk meg. Erre a megoldsra akkor lehet szksg, ha a feladat megoldsa sorn ritkn kell vltogatni a leszrt sorokat. 2. Adattbla sorainak levlogatsval A memriban trolt tbla (DataTable) objektum sorait is levlogathatjuk egy szrsnek megfelelen, s az eredmnyt elhelyezhetjk egy msik tbla objektumban vagy adatsorokat tartalmaz tmbben (DataRow[]). Erre rhatunk sajt, egyedi kdot, de hasznlhatjuk az adattbla Select metdusnak egyikt. DataRow[] Select(string filter), DataRow[] Select(string filter, string sorting), DataRow[] Select(string filter, string sorting, DataViewRowState state) Ezekben a filter egy szrfelttelt megad string, amely szintaxisa az SQL SELECT parancsok WHERE zradka mgtt lert felttelvel azonos. Nem megfelel alak szrfelttel futs kzben dob kivtelt. A sorting a szrt adatok rendezettsgt, a state a leszrend sorok sttuszt (j, trlt, mdostott, vltozatlan, eredeti, stb.) adja meg. 3. Adatktsben Egy adattbla szrst bellthatjuk azon kapcsolati (DataBindingSource) objektum Filter tulajdonsgval, amelyek az adatok megjelentsrt felels vezrlket ktik az adattblhoz. Ez a legrugalmasabb megolds, amelyet a gyakran vltoz szrfelttelek esetn hasznlunk. sszetett szrst bellt egyedi vezrl Az, hogy a fenti lehetsgek kzl melyikkel ljnk, az adott feladaton mlik. Itt elssorban hatkonysgi szempontok (memria ignynek s futsi idnek optimalizlsa) alapjn kell dnteni. A tovbbiakban a legutols technikt alkalmazzuk egy olyan feladatban, ahol a felhasznl adhat meg egy sszetett szrfelttelt a tblkat megjelent adatrcsokhoz.

62

Gregorics Tibor

sszetett megjelentsek

Tegyk lehetv, hogy az apartment tbla s a hozz tartoz price tbla sorait klnbz szempontok szerint szrve jelenthessk meg. Ksztsnk elszr egy olyan egyedi vezrlt (filtercontrol), amellyel a felhasznl ssze tud lltani egy szr felttelt. Ehhez ismernnk kell egyrszt azokat a tblkat, amelyeket szrni akarunk, azokat a szempontokat, amelyek alapjn egy tbla szrst el kell vgeznnk s vgl azokat a vezrlket, amelyekkel az egyes szempontok szrfelttele bellthat. Ezeket a vezrlket elhelyezzk a filtercontrol felletn, lehetv tesszk, hogy olyan tulajdonsgai legyenek, amelyekkel lekrdezhetjk az egyes tblk sszetett szrfeltteleit, s definilunk olyan esemnyeket, amelyek az egyes szrfelttelek megvltozst jelzik.2 Mi most az apartment s price tblk szrst akarjuk megoldani. Az apartmanokat a telepls neve, gyak szma s a jellemzk (features) alapjn, a price tblt pedig a brleti djak tl-ig hatrainak megadsval. Nyissunk egy j Windows Control Library projektet! Alaktsuk ki a felhasznli felletet az brnak megfelelen. Mindegyik szrsi szemponthoz tartozik egy vezrl. A cmke feliratok utalnak az egyes vezrlk szerepre. A vezrlk egymstl eltr mdon jelzik, hogy ket figyelembe kell-e venni a szrfelttel sszelltsnl vagy sem. Tbbsgknl ezt egy klnleges rtk (res sztring, 0 rtk) jelzi.

Ezt a vezrlt elkszthetnnk generikus formban is gy, hogy annak megfelel paramterezse rvn biztostsa a paramterknt megadott tblk paramterknt megadott szrfeltteleinek sszelltst.

63

Gregorics Tibor

sszetett megjelentsek

Ksztsk el a filterconrol kdjt! Definiljuk a kt esemnyt, amelynek kivltsrl majd mi gondoskodunk. Bevezetjk a filter tmbt, amely az egyes szr kritriumokat fogja tartalmazni sztring formban. Ha egy szr kritrium az res sztring, akkor az azt jelli, hogy arra az esetre nem vonatkozik megszorts. Azt, hogy melyik szrkritrium melyik indexen tallhat a filter-ben, a filterCriteria felsorolsi tpus mutatja.
public event EventHandler ApartmentFilterEvent; public event EventHandler PriceFilterEvent; private enum filterCriteria { city, bed, priceLow, priceHigh, features }; private string[] filter = new string[(int)(filterCriteria.features)+1];

Ezek utn definljuk azt a kt tulajdonsgot, amelyekrl az apartment, illetve a price tbla sszetett szrfelttele lekrdezhet. Mindkt tulajdonsg tmaszkodik a composite() metdusra, amely a szrkritriumokbl llt ssze egy szrfelttelt. Ezeket a tulajdonsgokat akkor rdemes lekrdezni, ha a szrfelttel megvltozst a megfelel esemny kivltdsa jelzi.
public string ApartmentFilter { get { return composite(filter[(int)filterCriteria.city], filter[(int)filterCriteria.bed], filter[(int)filterCriteria.features]); } } public string PriceFilter { get { return composite(filter[(int)filterCriteria.priceLow], filter[(int)filterCriteria.priceHigh]); } } private string composite(params string[] filters) { string result = ""; bool l = false; foreach(string str in filters) { if (str!="") { result += l ? " AND " + str : str; l = true; } } return result; }

64

Gregorics Tibor

sszetett megjelentsek

Az egyes szr kritriumokat a megfelel vezrlk rtknek megvltozsakor lltjuk be. Ilyenkor vltjuk ki a megfelel esemnyt is. res sztring a szvegdobozban azt jelzi, hogy nem akarunk szr kritriumot megadni, teht a szrkritrium is legyen res. Ellenkez eseteben a megfelel szrfelttelt kell belltani.
private void textBoxPriceHigh_TextChanged(...) { if(textBoxPriceHigh.Text != "") { try{ int n = int.Parse(textBoxPriceHigh.Text); filter[(int)filterCriteria.priceHigh] = string.Format("price<='{0}'",n); }catch(FormatException){ } } else filter[(int)filterCriteria.priceHigh] = ""; PriceFilterEvent(sender, e); } private void textBoxPriceLow_TextChanged(...) { if(textBoxPriceLow.Text != "") { try{ int n = int.Parse(textBoxPriceLow.Text); filter[(int)filterCriteria.priceLow] = string.Format("price>='{0}'", n); }catch (FormatException) { } } else filter[(int)filterCriteria.priceHigh] = ""; PriceFilterEvent(sender, e); }

A szmll vezrl 0 rtke jelzi azt, hogy nincs szrs megadva, hiszen nulla darab ggyal rendelkez apartman keresse rtelmetlen lenne. Ilyenkor a szrkritriumot res sztringre kell lltani, ellenkez esetben a megfelel szrfelttelt kell belltani.
private void numericUpDownBeds_ValueChanged(...) { if (numericUpDownBeds.Value != 0) { filter[(int)filterCriteria.bed] = string.Format("bed='{0}'", numericUpDownBeds.Value.ToString()); } else filter[(int)filterCriteria.bed] = ""; ApartmentFilterEvent(sender, e); } private void numericUpDownBeds_KeyPress(...) { numericUpDownBeds_ValueChanged(sender, e); }

65

Gregorics Tibor

sszetett megjelentsek

A kombinlt dobozban a lehetsges telepls neveken kvl egy res sztringet is mutatunk. Ez utbbi kivlasztsval jelezhetjk azt, hogy nem akarunk ezen szempont szerint szrni. A telepls nevek ilyen megjelentshez ltre kell hozni azt az adatforrst a city tblra, amit elzleg kiegsztnk az res nvvel, s ezen forrs alapjn generljuk azt a kapcsolati objektumot, amely a city tblt a kombinlt dobozhoz kti. Egy teleplsnv kivlasztsakor gondoskodni kell arrl, hogy a nvben szerepl esetleges aposztrf karaktert megklnbztessk a szrfelttelekben szerepl azon aposztrfoktl, amelyekkel az rtkeket kell zrjelezni. Ennek mdja a nvben szerepl aposztrf duplzsa. Az albbi kdban teht errl is gondoskodni kell a szrkritrium belltsa s a megfelel esemny kivltsa mellett.
private void comboBoxCity_SelectedIndexChanged(...) { if (comboBoxCity.Text != "") { string str = comboBoxCity.Text; int i = str.IndexOf('\''); while(i>-1) { str = str.Insert(i+1, "'"); i = str.IndexOf('\'',i+2); } filter[(int)filterCriteria.city] = string.Format("city='{0}'", str); } else filter[(int)filterCriteria.city] = ""; if (ApartmentFilterEvent != null) ApartmentFilterEvent(sender, e); }

Az ellenrzdoboz-lists vezrlvel gy lehet szrni az apartmanokat, hogy azokat a jellmezket kell belltani, amelyeket mindenkppen szeretnnk az apartmanban ltni. A be nem jellt jellemzk viszont nem azt jelentik, hogy azokat nem akarjuk az apartmanban, hanem azt, hogy azokrl nem kvnunk nyilatkozni. Teht mindig az sszes olyan apartmant meg kell mutatnunk, amely features kdjnak (a kd tovbbra is egy termszetes szm) bitmintjban mindazon helyeken 1-es ll, ahol a szrvezrlvel belltott jellemzk kdjnak bitmintjban is.
private int Code() { int code = 0; int n = checkedListBoxFeatures.Items.Count - 1; foreach (int k in checkedListBoxFeatures.CheckedIndices) { code |= (1 << n - k); } return code; }

66

Gregorics Tibor

sszetett megjelentsek

Ksztnk egy olyan felsorolt, amely rendre megadja az sszes olyan termszetes szmot, amelynek bitmintjban az ellenrzdobozlistban belltott helyeken 1-esek llnak.
public IEnumerator GetEnumerator() { int code = Code(); for(int k = 0; k< Math.Pow(2,checkedListBoxFeatures.Items.Count); ++k) { if ((k & code) == code) yield return k; } }

Ezt a felsorolt felhasznlva szerkesztjk meg a features-re vonatkoz szrst.


private void checkedListBoxFeatures_SelectedValueChanged(...) { string str = ""; if (Code() != 0) { foreach (object code in this) { str+= string.Format(" OR features ='{0}'",(int)code); } str = "(" + str.Substring(3) + ")"; } filter[(int)filterCriteria.features] = str; ApartmentFilterEvent(sender, e); }

Szksg lehet mg az sszes szrs trlsre. Ezt a Clear gombbal kezdemnyezhetjk. Ilyenkor nemcsak a filter tmbt kell kirteni, hanem az sszes szrsi szempontot megad vezrlt is alapllsba kell hozni.
private void buttonClear_Click(...) { for (int i = 0; i <= (int)(filterCriteria.features); ++i) { filter[i] = ""; } textBoxPriceHigh.Text = ""; textBoxPriceLow.Text = "" comboBoxCity.SelectedValue = 0; numericUpDownBeds.Value = 0; for (int i=0; i<checkedListBoxFeatures.Items.Count; ++i) checkedListBoxFeatures.SetItemChecked(i, false); ApartmentFilterEvent(sender, e); PriceFilterEvent(sender, e); }

67

Gregorics Tibor

sszetett megjelentsek

A kezdeti llapot belltsra a konstruktorban kerl sor.

public FilterControlForm() { InitializeComponent(); cityTableAdapter.Fill(apartmentsDataSet.city); apartmentsDataSet.city.Rows.Add(0, ""); object[] list = { "looking sea", "looking green", "terrace", "air condition" }; checkedListBoxFeatures.Items.AddRange(list); buttonClear_Click(buttonClick, new EvantArg e) }

Vgl trjnk vissza az eredeti projekthez, az apartmanokat s azok rait megjelent s karbantart kapcsolt tbls rlaphoz! Helyezzk el ennek felhasznli felletn a filtercontrol vezrlt (ToolBox). lestsk ennek mindkt egyedi esemnyt!
private void filterControlForm1_ApartmentFilterEvent(...) { apartmentBindingSource.Filter = filterControlForm1.ApartmentFilter; } private void filterControlForm1_PriceFilterEvent(...) { priceBindingSource.Filter = filterControlForm1.PriceFilter; }

68

Anda mungkin juga menyukai