GNavigia und Da­ten­ban­ken

Pro­gram­mie­ren Sie ei­ne Da­ten­ban­kan­bin­dung mit­tels COM




Wer sich mit dem Com­po­nent Ob­ject Mo­del, kurz «COM», aus­kennt, kann ei­ne un­abhängi­ge, zur Lauf­zeit nach­lad­ba­re Da­ten­ban­kan­bin­dung für GNavigia schrei­ben. Un­ter .NET geht das oh­ne Zwei­fel  kom­for­ta­bler, ist aber nicht zwin­gend er­for­der­lich. Ei­ne Bei­spie­lan­bin­dung, von der .NET-Pro­gram­me ab­lei­ten können, liegt GNavigia un­ter dem Na­men GpsDa­ta­ba­seAc­cess bei. Wenn Sie die Be­zeich­nung «Da­ten­ban­kan­bin­dung» sehr weit fas­sen, können Sie prak­tisch al­le Ar­ten von Aus­wer­tun­gen auf den Da­ten auf­setz­ten.
Das Ob­jekt muss da­zu le­dig­lich ei­nen pa­ra­me­ter­lo­sen Kon­struk­tor so­wie die IGpsDa­ta­ba­seAc­cess Schnitt­stel­le im­ple­men­tie­ren und die Re­gis­trie­rung als COM Ob­jekt um den Un­ter­schlüssel
  {8BE02F24-766C-4ba3-A744-42FF0E3F8564}
er­wei­tern. Wer von der o.a. Klas­se ab­lei­tet, erhält die Er­zeu­gung des Un­ter­schlüssels «frei Haus». Vor­sicht: Für Ih­re ei­ge­ne Da­ten­bank­klas­se benöti­gen Sie ei­ne an­de­re, neue GUID! Ei­ne GUID er­zeugt man mit dem Pro­gramm GUIDGEN.EXE, dass man über Goo­gle auf den Sei­ten von Mi­cro­soft fin­det. Es soll­te bei al­len COM-Ent­wick­lungs­tools da­bei sein! Ggf. ge­ne­riert das Neu­an­le­gen ei­nes .NET Pro­jekts, das für COM re­gis­triert wird, ei­ne sol­che GUID in der Da­tei As­sem­b­lyIn­fo.cs.
Die GUID wird aus­ge­wer­tet, wenn im Menü «Ex­tras/Da­ten­ban­kan­bin­dung» gewählt wird. Es er­scheint dann ei­ne Lis­te al­ler Ob­jek­te zur Aus­wahl, die die­sen Un­ter­schlüssel an­ge­ben. Die Auf­lis­tung dau­ert ei­nen klei­nen Mo­ment. Der dar­ge­stell­te Na­me ist der des COM Ob­jekts, auch als «Prog-ID» be­zeich­net; in­tern wird die GUID ge­spei­chert.
Wenn Sie ei­ne An­bin­dung ge­schrie­ben ha­ben, die zu­min­dest den kor­rek­ten Kon­struk­tor und die er­for­der­li­chen Metho­den im­ple­men­tiert so­wie die o.a. Voraus­set­zun­gen erfüllt, er­scheint nach der Aus­wahl ein wei­te­rer Menüpunkt «Da­ten­bank», der die ab­ge­bil­de­ten Un­ter­menüpunk­te enthält.
Zur Re­gis­trie­rung des COM-Objekts muss der Ent­wick­ler über Ad­mi­nis­tra­tor­rech­te verfügen, da die Ein­träge un­ter HKEY_CLASSES_ROOT er­fol­gen. Wer nicht als Ad­mi­nis­tra­tor ent­wi­ckeln will, der kann, zu­min­dest un­ter .NET, zur ers­ten Re­gis­trie­rung die Ent­wick­lungs­um­ge­bung als Ad­min­stra­tor star­ten und da­nach die Op­ti­on «Für COM re­gis­trie­ren» aus­schal­ten. Die Re­gis­trie­rung ist nur ein­mal nötig, um das COM Ob­jekt und das In­ter­face be­kannt zu ma­chen, da­nach er­folgt die Ent­wick­lung als ganz nor­ma­le Klas­sen­bi­blio­thek.

Steue­rung der Da­ten­bank­zu­grif­fe

Die Funk­tio­na­lität, die die Schnitt­stel­le IGpsDa­ta­ba­seAc­cess zur Verfügung stellt, lässt sich am Bes­ten am auf­ge­klapp­ten Menü do­ku­men­tie­ren; da­bei lie­fern die Ei­gen­schaf­ten (Pro­per­ties) die Tex­te für die Menüpunk­te, während die Metho­den die ei­gent­li­che Da­ten­bank­funk­tio­na­lität be­reit­stel­len. GpsI­ni­tia­li­ze, GpsSa­veDa­ta und GpsLoa­dDa­ta wer­den di­rekt aus dem Menü auf­ge­ru­fen. GpsConnect und GpsDis­connect wer­den zu ge­ge­be­ner Zeit ge­ru­fen, z.B. wenn der Be­nut­zer die Da­ten­ban­kan­bin­dung wech­selt, in­dem er aus dem Menü «Ex­tras/Da­ten­ban­kan­bin­dung» ei­nen an­de­ren Da­ten­ban­k­an­schluss auswählt. Le­dig­lich der Menüpunkt «Ab­mel­den von der Da­ten­bank», der in­tern GpsDis­connect auf­ruft, wird al­lein von GNavigia ver­wal­tet.

Ini­tia­li­sie­rung des Menüs

Das Menü wird ei­ner­seits aus der An­fra­ge an die Schnitt­stel­len­me­tho­den in­itia­li­siert, an­de­rer­seits aber auch aus In­for­ma­tio­nen aus der Re­gis­trie­rungs­da­ten­bank. Wenn ei­ne gülti­ge Da­ten­bank­ver­bin­dung aus­gewählt wird, er­scheint sie beim Wie­der­auf­star­ten der Appli­ka­ti­on, in­itia­li­siert aus der Re­gis­trie­rung.

La­den und Spei­chern der Da­ten

Zu­dem merkt sich GNavigia die Her­kunft der Da­ten, wes­halb nur beim erst­ma­li­gen Si­chern und ak­ti­vier­ter Da­ten­bank zwi­schen dem Spei­chern in die Da­ten­bank und dem in ei­ne Da­tei un­ter­schie­den wer­den muss. Wenn Sie sich für ei­ne Da­tei als Spei­cher­ort ent­schie­den ha­ben, können Sie im­mer noch aus dem Menü das Zurück­schrei­ben der Da­ten in die Da­ten­bank ver­an­las­sen, wo­durch je­doch nur der ak­tu­el­le Stand ge­si­chert wird. Beim Beant­wor­ten ei­ner Si­cher­heits­ab­fra­ge wird fol­ge­rich­tig nur in die Da­tei ge­schrie­ben.

Die IGpsDa­ta­ba­seAc­cess Schnitt­stel­le

Die IGpsDa­ta­ba­seAc­cess Schnitt­stel­le ist be­wusst ein­fach ge­hal­ten, so­dass COM Ser­ver kei­ne .NET In­ter­na ken­nen müssen. Was sie ken­nen müssen ist je­doch die in­ter­ne Da­ten­struk­tur von GNavigia, was we­gen der XML-Struk­tur, mit der al­le Da­ten über die Schnitt­stel­le aus­ge­tauscht wer­den, aber sehr fle­xi­bel ge­hand­habt wer­den kann. Das In­ter­face ist wie folgt de­fi­niert:
pu­blic in­ter­face IGpsDa­ta­ba­seAc­cess
{
// Read on­ly pro­per­ty: The da­ta­ba­se na­me
string GpsDa­ta­ba­seNa­me { get;}

// Read on­ly pro­per­ty: An ap­pro­pria­te tit­le
string GpsDa­ta­ba­seTit­le { get;}

// Read on­ly pro­per­ty: A kind of tool­tip
string GpsDa­ta­ba­seHint { get;}

// Read on­ly pro­per­ty: Me­nu item text for GpsI­ni­tia­li­ze
string GpsI­ni­tia­li­zeMe­nuText { get;}

// Read on­ly pro­per­ty: Me­nu item text for GpsSa­veDa­ta
string GpsSa­veDa­taMe­nuText { get;}

// Read on­ly pro­per­ty: Me­nu item text for GpsLoa­dDa­ta
string GpsLoa­dDa­taMe­nuText { get;}

// Me­nue cal­led me­thod to in­itia­li­ze da­ta­ba­se ac­cess.
// re­turns: Xm­lDo­cu­ments.Re­spon­se() if suc­cess­full
string GpsI­ni­tia­li­ze(int hwnd);

// Me­nue cal­led me­thod to connect to the da­ta­ba­se.
// re­turns: Xm­lDo­cu­ments.Re­spon­se() if suc­cess­full
string GpsConnect(int hwnd);

// Me­nue cal­led me­thod to dis­connect from the da­ta­ba­se
// re­turns: Xm­lDo­cu­ments.Re­spon­se() if suc­cess­full
string GpsDis­connect(int hwnd);

// Me­nue cal­led me­thod to sa­ve da­ta to da­ta­ba­se.
// re­turns: Xm­lDo­cu­ments.Re­spon­se() if suc­cess­full
string GpsSa­veDa­ta(int hwnd, string xm­lDa­taString);

// Me­nue cal­led me­thod to load da­ta from da­ta­ba­se.
// re­turns: An XML Da­ta Do­cu­ment String if suc­cess­full whe­re the
// string is a ful­ly qua­li­fied XML do­cu­ment.
// Mind the sche­ma de­fi­ni­ti­on!
string GpsLoa­dDa­ta(int hwnd);
}
Der for­ma­le Pa­ra­me­ter «hwnd» ist vom Typ int (Int32) und re­präsen­tiert je­nes Win­dowhand­le, das die Ur­ge­stei­ne der Fens­ter­pro­gram­mie­rung seit den aus­ge­hen­den 80er Jah­ren des vo­ri­gen Jahr­hun­derts ken­nen soll­ten. Es hat nur ei­nen ein­zi­gen Wert, nämlich ei­nen even­tu­ell not­wen­di­gen Dia­log an ei­nem Fens­ter fest­ma­chen zu können und so die Ket­te der durch mo­da­le Dia­lo­ge ab­ge­schal­te­ten Fens­ter nicht zu un­ter­bre­chen. Der .NET-Pro­gram­mie­rer kann das Hand­le di­rekt nut­zen, in­dem er ein Ob­jekt der  fens­ter­na­hen Klas­se «Tem­po­ra­ryOw­ner» an­legt, die selbst wie­der­um kei­ne an­de­re Auf­ga­be hat, als die Schnitt­stel­le «IWin32Win­dow» be­reit­zu­stel­len, die ih­rer­seits kei­ne an­de­re Auf­ga­be hat, als das Win­dowhand­le verfügbar zu ma­chen. COM Pro­gram­mie­rer ha­ben es an die­ser (und nur an die­ser) Stel­le ein­fa­cher: Sie cas­ten den Wert auf HWND und können ihn als pa­rent win­dow hand­le be­nut­zen.

Rück­ga­be­wer­te

Wer­fen Sie nie­mals ei­ne Aus­nah­me (Ex­cep­ti­on), die die Schnitt­stel­le verlässt. Sor­gen Sie dafür, dass die Aus­nah­men in­ner­halb der Schnitt­stel­le blei­ben und be­nut­zen Sie die vor­ge­se­he­nen XML-Doku­men­te als Rück­ga­be­wer­te, al­so «Re­spon­se» und «Er­rorRe­spon­se». Wer .NET be­nutzt, kann die ent­spre­chen­den Metho­den der
 KorKarNet.Uti­li­ties.dll 
auf­ru­fen. Da­mit ist das Ver­pa­cken der In­for­ma­ti­on be­son­ders ein­fach. Al­ler­dings bleibt die Auf­ga­be be­ste­hen, die Da­ten zu ei­nem GNavigia kon­for­men XML-Doku­ment zu­sam­men­zu­stel­len. Das The­ma «GNavigia für Fort­ge­schrit­te­ne» wid­met sich die­sem an­spruchs­vol­len The­ma.

Der har­te Kern der Da­ten­ban­kan­bin­dung

Die  Da­ten­ban­kan­bin­dung stellt im Kern zwei Metho­den zur Verfügung, die die Ar­beit des Da­ten­aus­tauschs über­neh­men:
 string GpsSa­veDa­ta(int hwnd, string xm­lDa­taString);
string GpsLoa­dDa­ta(int hwnd);

Da­ten in der Da­ten­bank spei­chern

Wid­men wir uns zunächst dem Spei­chern von Da­ten. Hier macht es sich GNavigia be­son­ders ein­fach, in­dem es ex­akt den­sel­ben Do­ku­mentin­halt in ei­ne Zei­chen­ket­te ver­packt, die das Pro­gramm auch auf Da­tei aus­ge­ben würde.

Ob ei­ne Da­ten­ban­kan­wen­dung die In­for­ma­tio­nen über Ob­jek­te und Lay­out aus­wer­ten will oder nur die primären Da­ten (Tracks, Track­punk­te und Weg­punk­te) berück­sich­tigt, ist letzt­lich je­der Appli­ka­ti­on selbst über­las­sen. Ei­ne Mi­schung aus da­tei­gestütz­ter Lay­out­de­fi­ni­ti­on und da­ten­bank­ge­spei­cher­ter Punkt­in­for­ma­ti­on ist nicht möglich. Denk­bar ist, dass die Da­ten­ban­kappli­ka­ti­on die Lay­out­de­fi­ni­ti­on in ei­ner ge­schlos­se­nen Zei­chen­ket­te im XML-For­mat in die Da­ten­bank schreibt. Al­ler­dings ist dann ei­ne Zu­ord­nung von Primär- und Lay­out­da­ten nur durch ei­ne Auf­trags­ver­wal­tung zu rea­li­sie­ren, die hier nicht be­han­delt wird.

Der Rück­ga­be­wert der Metho­de GpsSa­veDa­ta ist ei­ne XML-Zei­chen­ket­te, die die Lis­te der neu in die Da­ten­bank ein­ge­tra­ge­nen Punk­te enthält. Die­se be­kom­men beim In­sert ei­ne neue, da­ten­ban­kin­ter­ne ID, hier als glo­bal gülti­ge ID (GUID) be­zeich­net, die GNavigia mit­ge­teilt wer­den muss. Die­se Auf­ga­be über­nimmt das Tag «Iden­ti­fier» in der Ant­wort auf die An­fra­ge:
 <Iden­ti­fier iid="312" guid="AXZ67900jsds00" />
Da­rin ist «iid» die GNavigia-ID des Punk­tes und «guid» der glo­bal­ly un­i­que iden­ti­fier, den Sie als Be­nut­zer ver­ge­ben ha­ben, um das Ob­jekt in der Da­ten­bank iden­ti­fi­zie­ren zu können, soll­te al­so da­ten­bank­weit ein­deu­tig sein! Sie er­hal­ten Auf­schluss über die syn­tak­tisch kor­rek­te Aus­ga­be/Plat­zie­rung der GUID, in­dem Sie das Pro­gramm mit dem Pa­ra­me­ter
-guid
auf der Kom­man­do­zei­le auf­ru­fen und ei­ne Da­tei mit min­des­tens ei­nem Weg­punkt, Track, Track­punkt, Ob­jekt, Text­ob­jekt und ei­ner Ob­jek­tre­fe­renz spei­chern. An­sons­ten wird ei­ne lee­re, un­de­fi­nier­te GUID nicht in die Da­tei ge­schrie­ben. Bei die­ser Si­mu­la­ti­on erhält die GUID den Wert «"#In­va­lid"», der später beim Ein­le­sen der Da­tei wie­der in ei­nen lee­ren Wert überführt wird.

Da­ten aus der Da­ten­bank la­den

Prin­zi­pi­ell ist das La­de­for­mat iden­tisch mit dem Spei­cher­for­mat, doch lie­gen beim La­den nur die er­fass­ten, ex­ter­nen In­for­ma­tio­nen vor, so­dass die Da­ten kom­pak­ter auf­tre­ten. Da­bei han­delt es sich um das be­reits zu­vor erwähn­te XML-Doku­ment, das durch ei­ne Sche­ma­da­tei va­li­diert wer­den kann. Die  Sche­ma­da­tei ist al­ler­dings noch nicht rea­li­siert. Wenn Sie sich die Da­ten­struk­tur im Ab­schnitt «GNavigia für Fort­ge­schrit­te­ne» ge­nau­er an­se­hen, wer­den Sie fest­stel­len, dass Sie für die Nach­bil­dung der Da­ten­da­tei­en ei­ne wie auch im­mer ge­ar­te­te Auf­trags­ver­wal­tung benöti­gen, die die primären Beo­b­ach­tun­gen und die Ob­jekt­bil­dung, die Sie im Lau­fe der Zeit vor­neh­men, zu ei­ner lad­ba­ren Da­ten­struk­tur zu­sam­men­stellt.

Ei­ge­ne Ein­stel­lun­gen trans­por­tie­ren

Da­mit Sie Ein­stel­lun­gen und ei­ge­ne Vor­ga­ben aus der La­de­me­tho­de in die Spei­cher­me­tho­de übert­ra­gen können, können Sie in die La­de­da­tei ei­ne Ei­gen­da­ten­ken­nung ein­tra­gen. XML-Ele­men­te, die sich zwi­schen den Mar­kie­run­gen
 <Da­ta­ba­se>
</Da­ta­ba­se>
be­fin­den, wer­den vom Pro­gramm als Gan­zes ge­le­sen, aber nicht in­ter­pre­tiert. Beim Aus­ge­ben der Da­ten als Da­tei oder beim Zurück­schrei­ben in die Da­ten­bank wird die­ses Tag wie­der aus­ge­ge­ben. Da­mit ist es möglich, oh­ne den Ge­brauch glo­ba­ler Va­ria­blen Da­ten zwi­schen den Metho­den zum La­den und Spei­chern zu trans­por­tie­ren.

Hilfs­funk­tio­nen

Bei­spiel für die Ver­wen­dung der Klas­se Tem­po­ra­ryOw­ner:
string IDa­ta­ba­seAc­cess.GpsSa­veDa­ta(int hwnd, string xm­lDa­taString);
{
  Mes­sa­geBox.Show(new Tem­po­ra­ryOw­ner(hwnd),
    String.For­mat("The me­thod re­cei­ved a string of {0} by­tes.",
    xm­lDa­taString.Length));
  re­turn null;
}