Det går simpelt ud på at vi har et delphi program der snakker i en database. Jeg ville gerne have delphi til at tjekke for om tabellerne / tabel stukturen er korrekt i forhold til hvad delphi forventer - og hvis den ikke er, så opret det der mangler.
f.eks. Tabel: Fornavn, Efternavn, Telefon
Delphi forventer: Fornavn, Efternavn, Adresse, Telefon. -Og derfor skal delphi selv oprette Adresse feltet i databasen, hvorefter at database og delphi programmet er "synkrone" tabel struktur mæssigt.
Er der nogen der er faldet over en komponenter der f.eks. kan dette - eller har et godt forslag til at få det til at virke.
Den er heller ikke umulig, men er ret svær at koncentrerere. Da man laver rutinen i dag, men at det først er om et år eller to, at den kommer til rigtig virkning, ved at man på dét tidspunkt udvider databasen/programmet med noget som ikke er kendt i dag. Databasen/programmet forestilles at ligge på fx 20 enkeltstående maskiner, hvilket jo vil lave en del benarbejde, hvis man manuelt skal upgrade databaserne.
Vi benytter en interbase 7 database, hvilket godt kan anbefales. vi har et par triggere, samt et par compute by felter + alm. felter.
cursorWait; tnList:=TstringList.Create; db.getTableNames(tnList); exists:=(tnList.IndexOf('tab1')<>-1) and (tnList.IndexOf('tab2')<>-1) and (tnList.IndexOf('tab3')<>-1); //og viderer if exists then begin db.getFieldNames('contact',ds.prefix,tnList); exists:=(tnList.IndexOf('id')<>-1) and (tnList.IndexOf('name')<>-1) and (tnList.IndexOf('address')<>-1); end; tnList.Free; cursorNormal; //exists holder om rigtig db
Det her er noget kode som jeg bruger til at teste om der peges til en bestemt database. (Hvis du virkelig analyserer kode vil du se at den ikke tester på alle tabellernes felter, men det er ok til mit brug).
Det kunne bygges op til at osse lave "alter table" osv. Men du ville osse have brug for at læse felternes properties selvfølgelig, ikke noget lille projekt, for hvis du skal lave en alter, og vil beholde de felter der allerede er i en tabel skal de jo med i "alter" scriptet. Eller hvad?
Måske det er en ide lave en select sætning omgivet af en try sætning, så kan man fx gøre dette:
try query1.sql.clear; query1.sql.add('Select Fornavn from databasetabell'); query1.open; except Showmessage('Feltnavnet findes ikke'); end;
Hvis programmet ikke falder i except så findes den angivne kolonne. Så kan du lave et check for hvert feltnavn i dine tabeller, og hvis du falder i except sætningen så er det fordi du mangler en kolonne.(Eller at der er andre fejl(fx hvis en tabel mangler eller forbindelse til databasen mangler) men dem kan man fange først )
Mvh
PigBear
NB: Et spørgsmål: Er der nogen der kan sige mig hvordan man fanger hvilken type et felt i en tabell er, fx. telefon kolonnen i ovenstående eksempel. Kan man checke om det er af typen integer, varchar/string ellar float etc. ?
procedure finNum(var numInfo: TnumberInfo); //finalize number // find min,max udfra data var vi,vf: extended; i: integer; begin with numInfo do begin if not dynLength then if digInt+digFrac > 16 then digInt:=16-digFrac; if digInt > 3 then sep1000:=true else sep1000:=false; blankWhenZero:=false; notZero:=false; vi:=0; vf:=0; for i:=1 to digFrac do vf:=vf / 10 + 0.9; for i:=1 to digInt do vi:=vi*10+9; if dynLength then valTo:=vi+1 else valTo:=vi+vf; if signAllowed then valFrom:=-valTo else valFrom:=0; end; end; //fin num
procedure nullType; begin with fieldInfo.list[curIx] do begin name:=fname; typ:=typeNull; end; end; //null type
procedure unsupported; begin nullType; end; //unsupported
procedure numFixed; begin with fieldInfo.list[curIx] do begin name:=fname; typ:=typeNumber; with numInfo do begin digInt:=fields.FieldByName('numeric_precision').Value; digFrac:=fields.FieldByName('numeric_scale').Value; digInt:=digInt-digFrac; dynLength:=false; signAllowed:=true; //info(name+': number fixed '+toStr(digInt)+','+toStr(digFrac)); end; finNum(numInfo); end; end; //num fiexed
procedure numInt(signed: boolean); begin with fieldInfo.list[curIx] do begin name:=fname; typ:=typeNumber; with numInfo do begin digInt:=fields.FieldByName('numeric_precision').Value; digFrac:=0; dynLength:=false; signAllowed:=signed; //if signAllowed then s:='signed' else s:='unsigned'; //info(name+': integer '+toStr(numInfo.digInt)+' '+s); end; finNum(numInfo); end; end; //num int
procedure numDyn; begin with fieldInfo.list[curIx] do begin name:=fname; typ:=typeNumber; with numInfo do begin digInt:=fields.FieldByName('numeric_precision').Value; digFrac:=digInt; dynLength:=true; signAllowed:=true; //info(name+': number dynamic '+toStr(digInt)); end; finNum(numInfo); end; end; //num dyn
procedure numMoney; begin with fieldInfo.list[curIx] do begin name:=fname; typ:=typeNumber; with numInfo do begin digInt:=fields.FieldByName('numeric_precision').Value-4; digFrac:=4; signAllowed:=true; dynLength:=false; //info(name+': number money '+toStr(digInt)+',4'); end; finNum(numInfo); end; end; //num money
procedure date; var precision: integer; begin with fieldInfo.list[curIx] do begin name:=fname; typ:=typeDateTime; with dtInfo do begin //format:='(DK) dd-mm-yyyy hh:nn:ss.zzz'; if pos('microsoft access driver',lowercase(dsInfo.odbcInfo.driverName))<>0 then precision:=0 else precision:=fields.FieldByName('dateTime_precision').Value; //info(name+': date '+toStr(precision)); end; end; end; //date
procedure chr; begin with fieldInfo.list[curIx] do begin name:=fname; typ:=typeString; with strInfo do begin maxLength:=fields.FieldByName('character_maximum_length').Value; if fields.FieldByName('is_nullable').Value then minLength:=0 else minlength:=1; //info(name+': char, min: '+toStr(minlength)); end; end; end; //chr
procedure str; begin with fieldInfo.list[curIx] do begin name:=fname; typ:=typeString; with strInfo do begin if fields.FieldByName('is_nullable').Value then minLength:=0 else minlength:=1; maxLength:=fields.FieldByName('character_maximum_length').Value; if maxLength=0 then maxLength:=maximumStringLength; //info(name+': string, min: '+toStr(minlength)+' max: '+toStr(maxLength)); end; end; end; //str
procedure bit; begin with fieldInfo.list[curIx] do begin name:=fname; typ:=typeBool; //info(name+': boolean'); end; end; //bit
procedure sortFieldInfo; var i,j,ix: integer; t: TfieldInfoRecord; begin for i:=0 to fieldInfo.count-1-1 do begin ix:=i; for j:=i+1 to fieldInfo.count-1 do if lowercase(fieldInfo.list[ix].name) > lowercase(fieldInfo.list[j].name) then ix:=j; if ix<>i then begin t:=fieldInfo.list[i]; fieldInfo.list[i]:=fieldInfo.list[ix]; fieldInfo.list[ix]:=t; end; end; end; //sort field info
begin //get field types fields:= TADODataSet.Create(nil); curIx:=0; if prefix='' then connection.OpenSchema(TSchemaInfo(adSchemaColumns), VarArrayOf([Null,null,tableName,null]), EmptyParam, fields) else connection.OpenSchema(TSchemaInfo(adSchemaColumns), VarArrayOf([Null,prefix,tableName,null]), EmptyParam, fields); fieldInfo.count:=fields.RecordCount; setLength(fieldInfo.list,fieldInfo.count); curIx:=0; while not fields.EOF do begin fname:=fields.FieldByName('column_name').Value; ftype:=fields.FieldByName('data_type').Value; case ftype of 0,1: nullType; 2,3: numInt(true); 4,5: numDyn; 6: numMoney; 7: date; 8: str; 9,10: unsupported; 11: bit; 12,13: unsupported; 14: numFixed; 15: unsupported; 16: numInt(true); 17: numInt(false); 18,19: numInt(false); 20: numInt(true); 21: numInt(false); 128: unsupported; 129: chr; 130: str; 131: numFixed; 132: unsupported; 133: unsupported; 134: unsupported; 135: date; 136,137,138,139: unsupported; else unsupported; end; fields.Next; inc(curIx); end; fields.Free; sortFieldInfo; end; //TmyDb get field types
Det er godt nok revet ud af sammenhæng men det kan nok bruges, og så er det gratis :)
man kan sagtens lave den uden TmyDb classen, der skal så bare åbnes connection et andet sted, evt i selve getFieldTypes, eller connection som parameter.
Synes godt om
Ny brugerNybegynder
Din løsning...
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.