ADATBÁZIS-KEZELÉS ODBC DRIVERREL... 1 ODBC: OPEN DATABASE CONNECTIVITY (NYÍLT ADATBÁZIS KAPCSOLÁS)... 1 AZ ODBC FELÉPÍTÉSE... 2 ADATBÁZIS REGISZTRÁCIÓ... 2 PROJEKT LÉTREHOZÁSA... 3 A GENERÁLT PROJEKT FELÉPÍTÉSE... 4 REKORDOK MEGJELENÍTÉSE... 4 ADATCSERE A VEZÉRLİK ÉS AZ ADATTAGOK KÖZÖTT... 5 RENDEZÉS ÉS SZŐRÉS... 5 REKORD MÓDOSÍTÁSA... 6 REKORD BESZÚRÁSA... 6 A CEafView osztály módosítása... 6 EafView.h... 6 EafView.cpp... 7 EafView.cpp... 7 REKORD TÖRLÉSE... 8 EafView.cpp... 8 Szabóné Nacsa Rozália Email: nacsa@inf.elte.hu Honlap: people.inf.elte.hu/nacsa 2004. november Ebben a munkafüzetben megtanuljuk, hogyan használhatjuk Visual C++-ban megírt alkalmazásainkban a már meglévı adatbázisunkat ODBC meghajtóval. ODBC: Open Database Connectivity (nyílt adatbázis kapcsolás) Napjainkban számos adatbázis-kezelı létezik. Az elsı adatbázis-kezelı alkalmazások úgy készültek, hogy a forráskódba beírták az adott adatbázisra jellemzı eljáráshívásokat. (Application Program Interface hívások). Ha az alkalmazást egy új környezetben, egy másik adatbázisra szerették volna használni, akkor a programozóknak közvetlenül a forráskódban kellet átírni ezeket az eljárás- (API) hívásokat, annak ellenére, hogy az adatbázisokkal kapcsolatos tennivalók nagyon hasonlóak voltak. Az adatbázis-kezelık elterjedésével felmerült az igény az adatbázis-kezelık szabványos kezelésére. Az adatbázis-kezelés elsı szabványosítása az SQL nyelv (Standard Query Language) volt. Ezt a nyelvet az IBM fejlesztette ki és elsıként az ORACLE implementálta. Napjainkra az adatbázis-kezelı rendszerek legtöbbje lehetıvé teszi, hogy adatbázisát az SQL nyelven keresztül is elérhessük. Az ODBC egy másik adatbázis-kezelı szabvány. Itt egy szabványos eljárás készletet definiáltak az adatbázis eléréséhez. Az ilyen adatbázis-kezelı rendszerek esetében rendelkezünk egy olyan meghajtó programmmal - driverrel is, amely az adott adatbázishoz biztosítja az ODBC szabvány eljárásokat. A programozó ODBC hozzáférés esetén mindig ugyanazt az eljáráskészletet használja, így alkalmazása módosítás nélkül futtatható bármely más ODBC meghajtóval rendelkezı adatbázisra is. Ilyen ODBC eljárások például a rekordok bejárását végzı MoveFirst(), Move() eljárások. A hordozhatóság egyetlen feltétele, hogy az adatbázis-kezelı rendelkezzen ODBC meghajtóval. 1. oldal
Az ODBC felépítése Az ODBC architektúrája több szintő. Legfelül van a Connection szint. Ezen a szinten két adatot kell megadni. Az egyik adat az adatforrás neve (DSN Data Source Name). Ennek a névnek nem kötelezı megegyeznie az adatbázis tényleges, adathordozóra felírt nevével. A másik adattal azt mondjuk meg, hogy az adatbázisunkhoz melyik ODBC drivert szeretnénk használni. A futó alkalmazás az aktuális adatforrás ismeretében határozza meg, hogy melyik drivert kell betöltenie. Az ODBC eljárások mellet az alkalmazásban kiadhatunk SQL parancsokat is. ODBC architektúra Access driver Driver (meghajtó) MySQL driver DSN (adatforrás) Elemi alkalmazások fejlesztése adatbázis Adatbázis 1 A program indításakor a driver manager beolvassa az adatforrás adatait és betölti a drivert. driver 1 CDataBase példány CRecordSet példány Alkalmazás Függvényhívások Adatbázis 2 driver 2 Adatbázis regisztráció Azt a tevékenységet, melynek során összekapcsoljuk az adatbázist és az ODBC drivert (meghajtót) adatbázis regisztrációnak nevezzük. A regisztráció lépései 1. Vezérlıpult/Felügyeleti eszközök/odbc adatforrások 2. Felhasználói DSN fül / Hozzáadás gomb 3. Driver kiválasztása (MySQL ODBC 3.51) / Befejezés gomb 4. DSN (Data Source Name adatforrás név) konfikuráció DSN information Data Source Name: Elemi alkalmazások fejlesztése Description: MySQL ODBC 3.51 Driver DSN MySQL connection parameters Host: localhost Database name: eaf User: nacsa Pasword: xxxx Port: 3306 OK / OK 2. oldal
Projekt létrehozása File/New/ Projects MFC AppWizard.exe Project name: Eaf Step1: Single Document Document/View architecture support? Step 2/a: What database support would you like to import? Database view without file support DataSource gomb Step 2/b: Datasource ODBC (Elemi alkalmazások fejlesztése) Recordset type Snapshot OK Select database tables: diak Step 2/c: OK Saját jegyzeteim Step 3: What compound document support would you like to include? none What othr support would you like to include? Automation ActiveX controls Step 4: What features would you like to include? Docking toolbars Initial status bar Printing and print preview 3D controls How do you want your toolbars to look? normal How many files would you like on your recent file list? 4 Step 5: MFC Standards Yes please As a shared DLL Step 6: CEafView Class name: CEafView Base class: CRecordView Header file EafView.h Implementation file: EafView.cpp CEafSet Class name: CEafSet Base class: CRecordSet Header file EafSet.h Implementation file: EafSet.cpp style comments library Finish Forditás/Futtatás A projekt lefordítása után azonnal rendelkezésünkre állnak a legalapvetıbb adatbázis navigáló funkciók. 3. oldal
A generált projekt felépítése A CEafView osztály a CRecordView osztályból, a CEafSet osztály a CRecordSet osztályból származtatással jött létre. Az öröklıdés szabályai szerint a származtatott osztályok megöröklik az ısosztályok metódusait. A CRecordSet osztályban találhatók az ODBC-vel kapcsolatos metódusok (MoveFirst(), Move(), iseof(), Update()). Az alkalmazás-varázsló felismeri a megjelölt tábla (diak tábla) felépítését és a CEafSet osztályban deklarálja a tábla egyes oszlopainak megfelelı változókat. (m_diak_id, m_azon, m_nev). A CEafView osztályban definiált CEafSet-re mutató m_pset pointer segítségével hívhatjuk meg a CRecordSet (ODBC) eljárásait. Rekordok megjelenítése A fejlesztıkörnyezet ResourceView fülén, a Dialógus mappából válassza ki az IDD_EAF_FORM elemet és a már ismert módon tervezze meg az őrlapot. Control ID Style Variable name Type IDC_DIAK_ID Right, number m_pset->m_diak_id 1 long IDC_AZON left m_pset->m_azon CString IDC_NEV left m_pset->m_azon CString 1 A változók deklarálásához a Ctrl-t lenyomva tartva kattintson duplát a megfelelı vezérlıre. 4. oldal
Adatcsere a vezérlık és az adattagok között A CEafView adattagjai és az IDD_EAF_FORM vezérlıi között az adatcserét az UpdateData(TRUE) és az UpdateData(FALSE) eljárások végzik. Az osztályvarázsló a vezérlık és az adattagok közötti kapcsolatot a DoDataExchange() eljárás DDX_FieldText makróiban definiálja. void CEafView::DoDataExchange(CDataExchange* pdx) CRecordView::DoDataExchange(pDX); //AFX_DATA_MAP(CEafView) DDX_FieldText(pDX, IDC_DIAK_ID, m_pset->m_diak_id, m_pset); DDV_MinMaxLong(pDX, m_pset->m_diak_id, 1, 9999); DDX_FieldText(pDX, IDC_AZON, m_pset->m_azon, m_pset); DDV_MaxChars(pDX, m_pset->m_azon, 20); DDX_FieldText(pDX, IDC_NEV, m_pset->m_nev, m_pset); DDV_MaxChars(pDX, m_pset->m_nev, 30); //AFX_DATA_MAP Az UpdateData(FALSE) (a DoDataExchange makró definíciói alapján) az adattagokból a vezérlıkbe, az UpdateData(TRUE) pedig a vezérlıkbıl az adattagokba tölti át az adatokat. Az UpdateData() metódust a CRecordView osztály OnMove() metódusa hívja meg. Ezek a metódusok automatikusan bekerültek a projektbe, így a lefordított projekt azonnal alkalmas arra, hogy a diak táblát végigböngésszük. Rendezés és szőrés Adatbázis rekordjainak rendezett megjelenítéséhez a CRecordSet osztály m_strsort és m_strfilter CString típusú adattagjait kell a megfelelı értékre beállítani. Az m_strsort adattag nem más, mint az SQL parancsok ORDER BY klauzulája, míg az m_strfilter adattag tartalma a WHERE klauzula értéke. Példa SQL CRecordSet Select * from diak ORDER BY azon ASC; m_strsort = azon Select * from diak ORDER BY diak_id DESC; m_strsort = diak_id DESC Select * from diak WHERE nev Like Nagy% ; m_strfilter = nev Like Nagy% Egészítsük ki az alkalmazásunkat egy új menüponttal. A menü neve: Rendezés Menüpontok: Rendezés diak_id szerint (ID_SORT_DIAK_ID) Rendezés azonosító szerint (ID_SORT_AZON) Rendezés név szerint (ID_SORT_NEV) Vegyük hozzá a projektünkhöz az alábbi eseménykezelıket: void CEafView::OnSortDiakId() m_pset->m_strsort = "diak_id"; m_pset->requery(); //Nyitott record set frissítése az adatbázisból UpdateData(FALSE); //Vezérlık frissítése a record setbıl void CEafView::OnSortAzon() m_pset->close(); m_pset->m_strsort = "azon"; m_pset->open(); //Új record set feltöltése az adatbázisból UpdateData(FALSE); //Vezérlık frissítése a record setbıl 5. oldal
void CEafView::OnSortNev() m_pset->m_strsort = "nev"; m_pset->requery(); //Nyitott record set frissítése az adatbázisból UpdateData(FALSE); //Vezérlık frissítése a record setbıl Rekord módosítása Az adatbázis böngészése közben egyszerően módosíthajuk az egyes rekordok adatait. Az adatbázis módosítását a CRecordView OnMove() eljárása hajtja végre. Ez az eljárás akkor hívódik meg, amikor lelépünk a rekordról. A CRecordView OnMove metódusa meghívja az UpdateData(TRUE) eljárást, mely a vezérlıket átmásolja a CRecordSet megfelelı adattagjaiba, majd meghívja a a CRecordSet Move() eljárását. A Move() eljárás DoFieldExchange() metódusa az adattagokat átmásolja az adatbázisba. OnMove() UpdateData(TRUE); CRecordSet m_strsort m_strfilter Open() MoveFirst() Move() iseof() Update() Move() 3 1 CRecordView OnMove() Move() DoFieldExchange //makró CEafView Dialógus m_pset ablak ODBC driver DoFieldExchange 4 CEafSet m_diak_id m_azon m_name CRecordSet objektumra mutató pointer UpdateData(TRUE) 2 Ha a párbeszéd ablak valamely vezérlıjét csak olvashatóra állítjuk be, de ezt a mezıt új rekord beszúrásakor a felhasználónak kell kitölteni, akkor a vezérlı írásvédettségének beállítása attól függ, hogy éppen milyen feladatot hajtunk végre. Beszúrásnál fel kell oldani e mezı csak olvasható állapotát. Rekord beszúrása Vezessünk be m_addingrecord néven egy új privát BOOL adattagot a CEafView osztályban. Ebben az adattagban jelezzük, ha a Beszúrás mőveletet hajtottuk végre. Az adattag kezdıértéke legyen FALSE. A CEafView osztály módosítása EafView.h private: BOOL m_addingrecord; 6. oldal
recordset recordset vezérlık Elemi alkalmazások fejlesztése IV. Legyen az m_addingrecord adattag kezdetei értéke FALSE. EafView.cpp CEafView::CEafView() : CRecordView(CEafView::IDD) //AFX_DATA_INIT(CEafView) m_pset = NULL; //AFX_DATA_INIT // TODO: add construction code here m_addingrecord = FALSE; Egészítsük ki alkalmazásunk Rekord menüjét a Rekord beszúrása menüponttal: ID_RECORD_ADD, majd illesszük be a projektbe a menüpont eseménykezelıjét. EafView.cpp void CEafView::OnRecordAdd() //Létrehoz egy üres rekordot a record set-ben m_pset->addnew(); //"read only" vezérlık "engedélyezése" m_addingrecord = TRUE; CEdit* pctrl = (CEdit*)GetDlgItem (IDC_DIAK_ID); int result = pctrl->setreadonly(false); //Az aktuális rekord (üres) adatainak átmásolása a recordset-be. UpdateData(FALSE); Végül felüldefiniáljuk a CRecordView osztály OnMove() virtuális függvényét, melyben a beszúrás mőveletet elhagyva visszaállítjuk a csak olvasható mezı(k) írásvédettségét. View/ClassWizard Project: Eaf Class name: CEafView Object IDs: CEafView Messages: OnMove Add function/edit Code BOOL CEafView::OnMove(UINT nidmovecommand) if (m_addingrecord) m_addingrecord = FALSE; UpdateData(TRUE); if(m_pset->canupdate()) m_pset->update(); m_pset->requery(); UpdateData(FALSE); else //vezérlık //"read only" visszaállítása CEdit* pctrl = (CEdit*)GetDlgItem(IDC_DIAK_ID); pctrl->setreadonly(true); return TRUE; return CRecordView::OnMove(nIDMoveCommand); //Adatbázis frissítése //adatbázis //recordset 7. oldal
Rekord törlése Egészítsük ki alkalmazásunk Rekord menüjét a Rekord törlése menüponttal: ID_RECORD_DELETE, majd illesszük be a projektbe a menüpont eseménykezelıjét. EafView.cpp void CEafView::OnRecordDelete() m_pset->delete(); m_pset->move(); //Töröljük az aktuális rekordot //Ráállunk a következı rekordra, ha van ilyen if (m_pset->iseof()) m_pset->movelast(); if (m_pset->isbof()) m_pset->setfieldnull(null); UpdateData(FALSE); A munkafüzetben bemutatott projekt letölthetı a people.inf.elte.hu/nacsa/eaf/eaf4/projects/eafadmin_odbc címrıl. 8. oldal