Gambas Modules of minstens stukken ervan kan je zo universeel maken dat je ze gemakkelijk kan hergebruiken.
Bij gebruik van een databank (bv MySQL/MariaDB) moet je altijd code schrijven om een record aan te maken. Het gemeenschappelijke daarin is minstens het toevoegen van een record met een sleutel (record id).
Je kan de aanmaak van een nieuw record (dus met nieuwe gegevens) opsplitsen in twee delen:
- Aanmaken van een leeg record met een nieuw bekomen record nummer.
- Het aanvullen van dat nieuwe record met alle andere gegevens, een update dus.
De update procedure moet je waarschijnlijk toch ook maken om gegevens te kunnen wijzigen aan een record waarvan je de id kent.
Het aanroepend programma kan gewoon een “ModData.saveRecord(id, data)” gebruiken, de module splitst het op in twee delen.
Als de id gegevens is, wordt de update procedure aangeroepen.
Als de id = 0 moet er een nieuw record gemaakt worden, daarna de update procudure met de ondertussen verkregen id.
Een datamodule ModData bevat:
PRIVATE sLastError AS String
' ...
PUBLIC SUB addRecord(sTablename AS String, sKeyname AS String) AS Long
' adds a record to a given database, get the record id of the empty record
DIM sSql AS String
DIM myResult AS Result
'
sSql = "INSERT INTO " & db.Quote(sTablename) & " (" & sKeyname & ") VALUES(0)"
DEBUG sSql
'
TRY $hConData.Exec(sSql)
IF ERROR
sLastError &= "insert; " & Error.Text
RETURN 0
ELSE
sSql = "SELECT LAST_INSERT_ID() AS myId "
'myId" ' FROM " & db.Quote(sTablename)
TRY myResult = $hConData.Exec(sSql)
IF ERROR
sLastError &= "last id ?" & Error.Text
RETURN 0
ELSE
RETURN myResult!myId
ENDIF
ENDIF
DEBUG sLastError
END
De procedure geeft het aangemaakte recordnummer terug. Daarna kunnen de gegevens ingevuld worden, wat minder universeel is. Veel kans dat dit stuk code enkel intern vanuit de module aangeroepen wordt, je zou ze dus ook PRIVATE kunnen maken.
Fouten vraagt het aanroepend programma/aanroepende procedure op met getLastError(), wat geimplementeerd is als
PUBLIC SUB getLastError() AS String
'
RETURN sLastError
'
END
Alle procedures in de datamodule die een record moeten toevoegen in een database, kunnen deze zelfde functie gebruiken, mits aangeroepen met de juiste parameters voor de betreffende tabel.
Voorbeeld:
# |
Name |
Type |
Null |
Default |
Extra |
1 |
emp_id |
bigint(20) |
No |
None |
AUTO_INCREMENT |
2 |
emp_data1 |
int(11) |
No |
0 |
|
3 |
emp_data2 |
int(11) |
No |
0 |
|
4 |
emp_data3 |
char(1) |
Yes |
NULL |
|
5 |
emp_data4 |
varchar(11) |
Yes |
NULL |
|
6 |
emp_data5 |
datetime |
Yes |
NULL |
|
7 |
emp_data6 |
datetime |
Yes |
NULL |
|
8 |
emp_cre |
timestamp |
Yes |
CURRENT_TIMESTAMP |
|
9 |
emp_creby |
char(24) |
Yes |
NULL |
|
10 |
emp_upd |
datetime |
Yes |
NULL |
|
11 |
emp_updby |
char(24) |
Yes |
NULL |
|
Dit werkt op voorwaarde dat
- de key record_id een getal is, bv van het type bigint(20)
- de waarde van het veld record_id altijd automatisch wordt toegekend door de database (Auto Increment)
- er standaardwaarden voorzien zijn in de struktuur van de tabel (0, NULL, ..).
Als geen standaardwaarden voorzien zijn krijg je een foutmelding; de database krijgt enkel een opdracht om de key in te vullen en weet niet wat er met de andere velden moet gebeuren.
Andere dingen die je kan standaardiseren:
- Een foutmelding bijhouden (zie ook hierboven sLastError) en op laten vragen.
- Een record verwijderen dat een bepaalde keywaarde heeft.
- Opbouwen, openen en sluiten van de databaseverbinding
- Een keuze tussen verschillende datasets voorzien (bv laptop/netwerk, ontwikkeling/productie)
- enz.
Metadata
Dikwijls is het nuttig om te weten wanneer een record ontstaan is (creation date-time), en wie het gemaakt heeft (user). Als je daarvoor standaard velden opneemt in de database kan je die laten invullen vanuit deze record toevoegen-procedure. Het eenvoudigste voor het “createdon” veld is in de database als standaardwaarde “CURRENT_TIMESTAMP” in te stellen. Dan blijft nog het “createdby” veld, waar we de gebruikerslogin naam kunnen invullen (gb.user.name). Ofwel laat je een waarde opslaan die als parameter van de oproepende procedure komt, en kan het een andere vorm van gebruikers-id zijn, bv die waarmee in de applicatie ingelogd wordt.
- Database: employee
- Velden: id, naam, address, …, createdon, createdby
- Database: department
- Velden: id, building, floor, …, createdon, createdby
Dit is universeel; je kan employee.createdby of department.createdby enz. gebruiken; bij de AddRecord is het steeds dezelfde naam. Je moet dat dan voor alle tabellen zo doen!
Een andere mogelijkheid is de createdby optioneel te maken, zodat je ook nog minimale tabellen met enkel id kan houden.
En: als je niet de standaardnaam gebruikt, maar velden met een prefix voor de tabel gebruikt, moet je de veldnaam ergens vandaan halen.
- Database: employee
- Velden: emp_id, emp_naam, emp_address, …, emp_createdon, emp_createdby
- Database: department
- Velden: dep_id, dep_building, dep_floor, …, dep_createdon, dep_createdby
Gecombineerd:
PUBLIC SUB addRecord(sTablename AS String, sKeyname AS String, OPTIONAL sCreatedByField AS String) AS Long
' adds a record to a given database, get the record id of the empty record
DIM sSql AS String
DIM myResult AS Result
'
sSql = "INSERT INTO " & db.Quote(sTablename) & " (" & sKeyname
IF sCreatedByField
sSql &= "," & sCreatedByField & ") VALUES(0,&1)" ' & db.Quote(User.Name) & ")"
ELSE
sSql &= ") VALUE(0)"
ENDIF
'
DEBUG sSql
'
TRY $hconData.Exec(sSql, User.Name)
IF ERROR
sLastError &= "insert; " & Error.Text
RETURN 0
ELSE
sSql = "SELECT LAST_INSERT_ID() AS myId "
'
TRY myResult = $hConData.Exec(sSql)
IF ERROR
sLastError &= "last id ?" & Error.Text
RETURN 0
ELSE
RETURN myResult!myId
ENDIF
ENDIF
DEBUG sLastError
END
De procedure AddRecord krijgt een optionele parameter “sCreatedByField”.
Als die ingevuld is, wordt dat veld gebruikt om de gebruikersnaam in te bewaren; ‘User.Name’ kan je in Gambas altijd gebruiken en geeft de loginnaam van de gebruiker die het programma draait. Hier wordt die ingevuld vanuit AddRecord, zodat er van het oproepend programma niet aan gedacht moet worden, of ook de waarde niet vergeten of verkeerd ingevuld kan worden; zelfs als de update nadien niet werkt heb je al meta-informatie.
Als geen veldnaam wordt doorgegeven om de createdby informatie in op te slaan, wordt enkel de record_id ingevuld.
Upd: Ps: misschien gebruik ik ook beter geen tabelnaam-PREFIX in de veldnamen … (http://gambas.copyleft.be/blog/archives/1453)