“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”
Verwijderd
Wat ik op het moment doe is bij de eerste versie van mijn database het complete schema op te slaan in SVN, + een default script om de boel te vullen met wat data. Vanaf dat punt maak ik voor iedere database wijziging een patch. Wel handig dat die MS SQL management studio automatisch die files voor je kan maken
Vanaf dat punt is 't dus een schema + een hele lading patches. Om een bepaalde versie uit SVN te kunnen runnen is 't dus voornamelijk dit:
- checkout vanuit SVN
- nieuwe DB, create schema
- alle patches toepassen
Vrij bewerkelijk, en ook nog eens foutgevoelig. Ik hoop dat er betere oplossingen zijn
Op zich niet echt een nette manier, maar het werkt...
Ik wil niet met create scripts etc. prutsen omdat ik zelf zo nu en dan de database van productie erin knal, en dan kloppen die scripts toch niet meer.
[ Voor 28% gewijzigd door prutsger op 06-05-2008 13:40 ]
Als er DB aanpassingen moeten gebeuren, pas ik het model aan. Genereer ik een nieuw DB script via dat model, maak ik een nieuwe DB mbhv dat script, en compare ik de nieuwe DB met de bestaande (live) DB (Via tools van RedGate).
Ik laat RedGate dan een script genereren die de live DB naar de nieuwe versie kan brengen (patch). Ik zorg ervoor dat die patch ook een versie-nummer insert in een 'version' tabel.
De patch wordt ook in VSS geplaatst, en we hebben afgesproken dat de patch een filenaam krijgen die er als volgt uitziet: <project_naam><versienummer>.sql
Ik heb dan ook een tooltje gebouwd die me toelaat om een nieuwe DB te bouwen (mbhv een baseline-script waarop dan alle patches in de juiste volgorde worden uitgevoerd), of een bestaande DB te upgraden. (Kijkt in die version tabel in welke versie de DB nu staat, en gaat dan alle latere patches gaan toepassen).
Werkt tot nu toe helemaal goed.
(Trouwens, in het verleden is hier al eens een topic over geopend, ff kijken of ik het terugvind)
edit: hm, is een wat 'algemener' topic: [Databases] Ontwikkeling
[ Voor 4% gewijzigd door whoami op 06-05-2008 13:53 ]
https://fgheysels.github.io/
RedGate heeft wat dat betreft wel lekkere tools om mee te werken.
“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”
Hierbij moet het dus mogelijk zijn om de database vanaf versie 1.0 naar versie x.xx te kunnen upgraden. Hierbij word het schema aangepast (tabellen, velden toegevoegd verwijderd) en eventueel configuratie data of default data geinsert, geupdate of gedelete.
Wij regelen alles vanuit de code, en niet via sql scripts. Mede omdat we meerdere database server typen ondersteunen en alle wijzigingen via een aparte laag verlopen.
Per versie maken we een klasse die de gewenste databasewijzigingen voor die versie kan uitvoeren. bij het openen van de database worden dan instanties van alle klasses boven het huidige versienummer opgehaald en de database upgrades worden van beneden naar boven uitgevoerd. Hierna wordt het versienummer van de database bijgewerkt naar de huidige versie.
Voor het doorvoeren van een database wijziging doen wij dus het volgende:
- Nieuwe klasse aanmaken
- Implementeer Interface voor datbasewijzigingen
- Schema bijwerk methode implementeren
- Data bijwerk methode implementeren
- nieuwe database versienummer opgeven
Het voordeel is dat we op elk willekeurig moment een database kunnen maken van welke versie dan ook, dit is bijvoorbeeld nodig voor het terugzetten van een oude backup in een nieuwere versie van het pakket.
De versie historie is dan gewoon terug te vinden in de code.
Verwijderd
Hier zit ik zelf ook aan te denken. Wij hebben nu gewoon de sql scripts in VSS staan, en in de applicatie een simpele procedure, die aan de hand van een date/versie stamp in de db begint te updaten. Scripts zitten dan gewoon in de code " verwerkt". Data aanpassingen etc, programmeren we er dan met de " hand" bij.Serpie schreef op dinsdag 06 mei 2008 @ 14:21:
Voor het doorvoeren van een database wijziging doen wij dus het volgende:
- Nieuwe klasse aanmaken
- Implementeer Interface voor datbasewijzigingen
- Schema bijwerk methode implementeren
- Data bijwerk methode implementeren
- nieuwe database versienummer opgeven
Dus is meer routines als
UpdateDB_v1_v2
UpdateDB_v2_v3
etc. die dan sequentieel (indien nodig) worden aangeroepen door een centrale UpdateDB procedure.
Wijzingen in de DB Scheme krijg ik eruit door een zelf gemaakte tool, die aan de hand van sql statemens, of inlezen van db scheme's de verschillen er als sql script uitgooid.
( eventuele drop tables/indices staan daar standaard in met commentaar
Jouw idee/jullie werkwijze klinkt erg goed.,
cool, 1e opzet begint al wat te worden
DBUpdater.RegisterClass(Update0to1);
DBUpdater.RegisterClass(Update1to2);
DBupdater.Execute();
werkt nog redelijk ook, nu nog uitwerken
[ Voor 22% gewijzigd door Verwijderd op 06-05-2008 17:31 ]
Ik vind het op zich ook wel een mooi idee. Denk wel dat ik het zou implementeren met SQL files die ik dan gewoon mee compileer als embedded resources of iets dergelijksVerwijderd schreef op dinsdag 06 mei 2008 @ 14:45:
[...]
Hier zit ik zelf ook aan te denken. Wij hebben nu gewoon de sql scripts in VSS staan, en in de applicatie een simpele procedure, die aan de hand van een date/versie stamp in de db begint te updaten. Scripts zitten dan gewoon in de code " verwerkt". Data aanpassingen etc, programmeren we er dan met de " hand" bij.
Dus is meer routines als
UpdateDB_v1_v2
UpdateDB_v2_v3
etc. die dan sequentieel (indien nodig) worden aangeroepen door een centrale UpdateDB procedure.
Wijzingen in de DB Scheme krijg ik eruit door een zelf gemaakte tool, die aan de hand van sql statemens, of inlezen van db scheme's de verschillen er als sql script uitgooid.
( eventuele drop tables/indices staan daar standaard in met commentaar)
Jouw idee/jullie werkwijze klinkt erg goed.,
Ik weet niet in welke omgeving je werkt, maar met bijvoorbeeld C# kan je bijvoorbeeld ook iets met Attributes doen (Met Java's Annotations zal het ook wel kunnen). Je laat dan bij het opstarten gewoon de assembly(s) door zoeken naar classes die een bepaalde Attribute hebben en je Update Classes laat je er dan als volgt uit zien.
cool, 1e opzet begint al wat te worden
DBUpdater.RegisterClass(Update0to1);
DBUpdater.RegisterClass(Update1to2);
DBupdater.Execute();
werkt nog redelijk ook, nu nog uitwerken
1
2
3
4
5
| [DBUpdate( OldVersion = "1.0.0" , NewVersion = "1.0.1" )] DBVersionUpdate100to101 : IDBUpdater { ..... } |
Het voordeel is dat je dan niet telkens al je classes hoeft te registreren, maar je gewoon een nieuwe class kan defineren.
[ Voor 3% gewijzigd door Woy op 06-05-2008 20:23 ]
“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”
Verwijderd
In dit project gaat het om Delphi, en daar heb je zoiets degelijks niet.rwb schreef op dinsdag 06 mei 2008 @ 20:19:
[...]
Het voordeel is dat je dan niet telkens al je classes hoeft te registreren, maar je gewoon een nieuwe class kan defineren.
Wil idd wel iets vinden om dat registreren te vermijden.
Zit wel te denken om 2 scheme update methods te implementeren
iets van
1
2
3
| function SchemeUpdateBeforeData : boolean; function DataUpdate : boolean; function SchemeUpdateAfterData : boolean; |
omdat je in sommige gevallen eerst met bestaande data moet doen alvorens een table te alteren/droppen etc.
[ Voor 30% gewijzigd door Verwijderd op 06-05-2008 20:57 ]
Ik weet niet of je in Delphi wel Runtime Type Information op kan vragen? maar anders kan je mischieen gewoon in je executable alle types die de IDBUpdater interface implementeren opzoeken. Je moet dan in je IDBUpdater alleen ook nog properties defineren die de versies aangeven zodat je kan sorteren.Verwijderd schreef op dinsdag 06 mei 2008 @ 20:54:
[...]
In dit project gaat het om Delphi, en daar heb je zoiets degelijks niet.
Wil idd wel iets vinden om dat registreren te vermijden.
Zit wel te denken om 2 scheme update methods te implementeren
iets van
code:
1 2 3 function SchemeUpdateBeforeData : boolean; function DataUpdate : boolean; function SchemeUpdateAfterData : boolean;
omdat je in sommige gevallen eerst met bestaande data moet doen alvorens een table te alteren/droppen etc.
“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”
Data wordt opgeslagen in XML, dus prima te gebruiken in een versiebeheersysteem. Wij gebruiken het nu een paar maanden, en zijn er heel erg tevreden over.
The process of preparing programs for a digital computer is especially attractive, not only because it can be economically and scientifically rewarding, but also because it is an aesthetic experience much like composing poetry or music.
Verwijderd
Goed plan, gaan we wat mee doen idd.rwb schreef op woensdag 07 mei 2008 @ 09:01:
[...]
Ik weet niet of je in Delphi wel Runtime Type Information op kan vragen? maar anders kan je mischieen gewoon in je executable alle types die de IDBUpdater interface implementeren opzoeken. Je moet dan in je IDBUpdater alleen ook nog properties defineren die de versies aangeven zodat je kan sorteren.
die properties waren er al, moest immers al sorteren
Verwijderd
Bij onze Delphi applicaties gebruiken we een veel simpelere methode, iets als:Verwijderd schreef op woensdag 07 mei 2008 @ 10:01:
Goed plan, gaan we wat mee doen idd.
die properties waren er al, moest immers al sorteren
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
| type TVersionProc = procedure; TVersionObject = class private FProc : TVersionProc; public constructor Create(AProc: TVersionProc); property Proc: TVersionProc read FProc; end; TVersionList = class(TStringList) public procedure AddVersion(AName: String; AProc: TVersionProc); destructor Destroy; override; end; var VersionList: TVersionList; implementation { TVersionObject } constructor TVersionObject.Create(AProc: TVersionProc); begin FProc := AProc; end; { TVersionList } procedure TVersionList.AddVersion(AName: String; AProc: TVersionProc); begin AddObject(AName,TVersionObject.Create(AProc)); end; destructor TVersionList.Destroy; begin while Count<>0 do begin Objects[0].Free; Delete(0); end; inherited Destroy; end; initialization VersionList := TVersionList.Create; VersionList.AddVersion('', ToVersion_v3_s1); VersionList.AddVersion('v3.s1', ToVersion_v3_s2); VersionList.AddVersion('v3.s2', ToVersion_v3_s3); [...] VersionList.AddVersion('v3.s32', ToVersion_v3_s33); VersionList.AddVersion('v3.s33', nil); finalization VersionList.Free; end. |
en dan
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| procedure TfrmMain.btnUpdateClick(Sender: TObject); var iVersion, i: Integer; begin try iVersion := VersionList.IndexOf(GetVersion); if iVersion = VersionList.Count-1 then begin AddToLog('The version is already the newest'); end else if iVersion = -1 then begin AddToLog('This version is unknown to this AutoUpdate'); end else begin for i := iVersion to VersionList.Count-2 do begin StartTransaction; TVersionObject(VersionList.Objects[i]).Proc; SetVersion(VersionList[i+1]); CommitTransaction; end; end; AddToLog( 'Database update ended'); except RollBackTransaction; raise; end; end; |
Dan hoef je je niet te bekommeren over RTTI, nieuwe classes voor elke update of interfaces. Gewoon een procedure toevoegen voor elke database update.
Werkt al een jaar of 10 uit de kunst, en is prima in het version control systeem op te slaan.
Maar ik ben idd ook wel geintereseerd in ervaringen
“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”
De features (beetje marketing, maar toch wel waar wat ze roepen):
* Works well with code branches
* A Database Refactoring IDE-Plugin (short demo)
* Isn't DBMS-specific
* Allows you to manage production data as well as various test datasets
* Works in an environment where multiple machines will be attempting to migrate the database concurrently
* Supports automated change-applying or generation of SQL scripts that can be approved and applied by a DBA
* Supports rolling back changes
* Can create database ”diff“s and can generate change logs from them
* Can auto-generate database change documentation
nope