{"id":55001280,"date":"2021-02-01T00:00:00","date_gmt":"2021-02-17T18:40:17","guid":{"rendered":"http:\/\/access-im-unternehmen.aix-dev.de\/aiu\/?p=1280"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-30T00:00:00","slug":"Metadaten_per_Zusatztabelle_verwalten","status":"publish","type":"post","link":"https:\/\/access-im-unternehmen.de\/Metadaten_per_Zusatztabelle_verwalten\/","title":{"rendered":"Metadaten per Zusatztabelle verwalten"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/vg07.met.vgwort.de\/na\/7c62bf2db1374078a2a10fcff9e352a2\" width=\"1\" height=\"1\" alt=\"\"><\/p>\n<p><b>Im Laufe der Zeit k&ouml;nnen sich einen Menge Daten ansammeln, die Sie in Zusammenhang mit Kunden, Produkten oder &auml;hnlichen Entit&auml;ten speichern wollen. Dabei m&ouml;chten Sie vielleicht nicht f&uuml;r jede neue Eigenschaft ein neues Feld anlegen und damit den Tabellenentwurf &auml;ndern. Das gilt umso mehr, wenn eine Anwendung bereits von vielen Kunden genutzt wird. Es gibt jedoch eine Alternative: Sie k&ouml;nnen eine zus&auml;tzliche Tabelle hinzuf&uuml;gen, die in jedem Datensatz eine Eigenschaft mit dem jeweiligen Wert f&uuml;r die Entit&auml;t speichert. Die Frage ist nur: Wie k&ouml;nnen wir diese Daten genauso nutzen, als wenn diese wie &uuml;blich in der gleichen Tabelle wie der Kunde oder das Produkt gespeichert werden<\/b><\/p>\n<p>Nehmen wir an, Sie m&ouml;chten einer Kundentabelle zwei neue Felder hinzuf&uuml;gen, mit denen Sie festlegen, wann der Kunde sich f&uuml;r den Newsletter angemeldet hat und wann er sich wieder abgemeldet hat. Sie wollen aber nicht die Kundentabelle anpassen, weil Sie das in der Vergangenheit schon &ouml;fter gemacht haben und dies immer mit viel Aufwand verbunden ist.<\/p>\n<p>Stattdessen wollen Sie eine L&ouml;sung schaffen, mit der Sie langfristig zwar nach Bedarf neue Felder hinzuf&uuml;gen k&ouml;nnen, aber nicht jedesmal den Entwurf der Kundentabelle &auml;ndern m&uuml;ssen.<\/p>\n<h2>L&ouml;sung per Extra-Tabelle<\/h2>\n<p>Die L&ouml;sung ist eine zus&auml;tzliche Tabelle, welche ausschlie&szlig;lich Metadaten zu den Elementen der Haupttabelle speichert. Wie muss eine solche Tabelle aussehen, wenn wir dort nach Wunsch verschiedene Attribute mit ihren Werten hinzuf&uuml;gen wollen <\/p>\n<h2>Anforderungen an die Metadaten-Tabelle<\/h2>\n<p>Die erste Anforderung ist, dass die Daten der Metadaten-Tabelle den Eintr&auml;gen der Haupttabelle zugeordnet werden k&ouml;nnen m&uuml;ssen. Die Metadaten-Tabelle, nennen wir Sie hier <b>tblKundenMeta<\/b>, erh&auml;lt also neben dem Prim&auml;rschl&uuml;sselfeld <b>KundeMetaID <\/b>ein Fremdschl&uuml;sselfeld namens <b>KundeID<\/b>. Au&szlig;erdem wollen wir den Namen des Attributs und den Wert des Attributs in der Tabelle speichern. Dazu legen wir zwei weitere Felder namens <b>Attributname <\/b>und <b>Attributwert <\/b>an. Dem Feld <b>Attributname <\/b>weisen wir logischerweise den Felddatentyp <b>Kurzer Text <\/b>zu.<\/p>\n<p>Aber welchen Datentyp soll das Feld <b>Attributwert<\/b> erhalten &#8211; immerhin sollen dort gegebenenfalls Daten mit verschiedenen Datentypen gespeichert werden In diesem Fall k&ouml;nnen wir nur den Datentyp <b>Kurzer Text <\/b>w&auml;hlen, da alle anderen Datentypen Einschr&auml;nkungen haben &#8211; zum Beispiel k&ouml;nnen Sie Zahlenfelder nicht mit Texten f&uuml;llen, aber umgekehrt schon.<\/p>\n<h2>Jedes Attribut nur einmal pro Datensatz<\/h2>\n<p>Grunds&auml;tzlich sollten wir f&uuml;r die Kombination des Fremdschl&uuml;sselfeldes (hier <b>KundeID<\/b>) und <b>Attributname <\/b>einen eindeutigen Index festlegen, damit jedes Attribut f&uuml;r jeden Kunden nur einmal angelegt werden kann &#8211; so, wie es auch in einem einfachen Feld direkt in der Kundentabelle der Fall ist.<\/p>\n<p>Andererseits stellt sich die Frage, ob es nicht auch Anwendungsf&auml;lle gibt, in denen mehrere Werte f&uuml;r ein Attribut ben&ouml;tigt werden, die unter dem gleichen Attributnamen abrufbar sein sollen. Dann w&auml;re ein zusammengesetzter, eindeutiger Index nicht sinnvoll. Und was, wenn es zwar Felder gibt, die nur einmal vorkommen d&uuml;rfen, andere aber mehrmals Dies m&uuml;ssten wir in der Prozedur pr&uuml;fen und behandeln, mit der wir Daten zu der Meta-Tabelle hinzuf&uuml;gen.<\/p>\n<h2>Datenmodell von Haupt- und Metatabelle<\/h2>\n<p>F&uuml;r unser Beispiel sieht das Datenmodell wie in Bild 1 aus. Die Beziehung zwischen den Tabellen wird &uuml;ber das Fremdschl&uuml;sselfeld <b>KundeID <\/b>der Tabelle <b>tblKundenMeta <\/b>hergestellt. F&uuml;r diese Beziehung legen wir referentielle Integrit&auml;t mit L&ouml;schweitergabe fest.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2021_01\/pic_1280_001.png\" alt=\"Datenmodell mit Metatabelle\" width=\"424,7115\" height=\"260,2745\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 1: Datenmodell mit Metatabelle<\/span><\/b><\/p>\n<p>Wenn der Benutzer dann einen Datensatz der Tabelle <b>tblKunden <\/b>l&ouml;scht, werden die damit verkn&uuml;pften Datens&auml;tze der Tabelle <b>tblKundenMeta <\/b>automatisch mitgel&ouml;scht.<\/p>\n<h2>Bearbeiten der Metadaten &uuml;ber die Benutzeroberfl&auml;che<\/h2>\n<p>Die flexibelste Art, die Metadaten in einem Formular anzuzeigen, ist ein Unterformular, dass alle Datens&auml;tze der Tabelle <b>tblKundenMeta <\/b>anzeigt, die zu dem im Hauptformular geh&ouml;renden Datensatz der Tabelle <b>tblKunden <\/b>geh&ouml;ren. Zum Erstellen des Unterformulars gehen Sie wie folgt vor:<\/p>\n<ul>\n<li>Legen Sie ein neues Formular namens <b>sfmKundenMitMetadaten <\/b>an.<\/li>\n<li>Stellen Sie die Eigenschaft <b>Datensatzquelle <\/b>auf die Tabelle <b>tblKundenMeta <\/b>ein.<\/li>\n<li>Ziehen Sie die Felder <b>Attributname <\/b>und <b>Attributwert <\/b>in den Detailbereich des Entwurfs.<\/li>\n<li>Stellen Sie die Eigenschaft <b>Standardansicht <\/b>auf <b>Datenblatt <\/b>ein.<\/li>\n<li>Schlie&szlig;en und speichern Sie das Unterformular.<\/li>\n<\/ul>\n<p>Den Entwurf des Unterformulars mit den Eigenschaften finden Sie in Bild 2.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2021_01\/pic_1280_002.png\" alt=\"Entwurf des Unterformulars sfmKundenMitMetadaten\" width=\"599,593\" height=\"312,063\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 2: Entwurf des Unterformulars sfmKundenMitMetadaten<\/span><\/b><\/p>\n<p>Das Hauptformular legen Sie wie folgt an:<\/p>\n<ul>\n<li>Legen Sie ein neues Formular namens <b>frmKundenMitMetadaten <\/b>an.<\/li>\n<li>Stellen Sie die Eigenschaft <b>Datensatzquelle <\/b>auf <b>tblKunden <\/b>ein.<\/li>\n<li>Ziehen Sie alle Felder der Tabelle in den Entwurf.<\/li>\n<li>Ziehen Sie das Formular <b>sfmKundenMitMetadaten <\/b>aus dem Navigationsbereich in den Formularentwurf.<\/li>\n<li>Speichern und schlie&szlig;en Sie das Formular.<\/li>\n<\/ul>\n<p>Wenn die Tabellen korrekt verkn&uuml;pft sind und Sie nun das Unterformular-Steuerelement markieren, zeigen die Eigenschaften <b>Verkn&uuml;pfen von <\/b>und <b>Verkn&uuml;pfen nach <\/b>beide den Wert <b>KundeID <\/b>an (siehe Bild 3).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2021_01\/pic_1280_003.png\" alt=\"Entwurf des Hauptformulars frmKundenMitMetadaten\" width=\"700\" height=\"284,7458\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 3: Entwurf des Hauptformulars frmKundenMitMetadaten<\/span><\/b><\/p>\n<h2>Attribute eingeben<\/h2>\n<p>Wechseln Sie in die Formularansicht des Hauptformulars, k&ouml;nnen Sie erste Daten eintragen. Beginnen Sie mit denen auf der linken Seite. Danach f&uuml;gen wir rechts zuerst einen Attributnamen und dann den Wert ein. Auf diese Weise legen wir die Eigenschaften <b>E-Mail <\/b>und <b>Newsletteranmeldung <\/b>mit den gew&uuml;nschten Weren (siehe Bild 4).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2021_01\/pic_1280_004.png\" alt=\"Eingabe von Attributen und Attributwerten\" width=\"599,593\" height=\"307,4835\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 4: Eingabe von Attributen und Attributwerten<\/span><\/b><\/p>\n<h2>Alternative Eingabem&ouml;glichkeit<\/h2>\n<p>Wenn Sie nun entscheiden, dass Sie f&uuml;r neue Metadaten zwar keine &Auml;nderungen am Datenmodell vornehmen m&ouml;chten, aber sehr wohl an der Benutzeroberfl&auml;che, wird es viel aufwendiger.<\/p>\n<p>Aber warum sollte man &Auml;nderungen an der Benutzeroberfl&auml;che tolerieren, wenn man das Datenmodell nicht antasten m&ouml;chte Es kann beispielsweise sein, dass das Backend nicht so einfach angepasst werden kann, weil es beispielsweise ein SQL Server-Backend ist. Beim Frontend hingegen ist das kein Problem &#8211; wenn es vern&uuml;nftig programmiert ist, k&ouml;nnen Sie dieses einfach ersetzen, ohne dass der Betrieb eingeschr&auml;nkt wird.<\/p>\n<p>Daher wollen wir nun die beiden neuen Attribute E-Mail und Newsletteranmeldung wie die Felder der Tabelle <b>tblKunden <\/b>im Formular anzeigen. Dazu legen wir ein neues Formular namens <b>tblKundenMitMetafeldern <\/b>an.<\/p>\n<p>Wenn wir eine Datensatzquelle f&uuml;r alle Felder erhalten wollen, ben&ouml;tigen wir eine entsprechend formulierte Abfrage. Diese sollte also nicht nur die Felder der Tabelle <b>tblKunden <\/b>enthalten, sondern auch noch zwei Felder namens <b>EMail <\/b>und <b>Newsletteranmeldung<\/b>.<\/p>\n<p>Um es kurz zu machen: Eine solche Abfrage, die gleichzeitig auch noch aktualisierbar ist, l&auml;sst sich nicht erstellen. Aktualisierbar muss diese aber sein, weil wir auch Daten in das Formular eingeben wollen.<\/p>\n<p>Also legen wir f&uuml;r die beiden Attribute <b>E-Mail <\/b>und <b>Newsletteranmeldung <\/b>ungebundene Textfelder an, die wir beim Anzeigen des Datensatzes mit den Werten der Tabelle <b>tblKundenMitMetadaten <\/b>f&uuml;llen.<\/p>\n<p>Wenn der Benutzer die Inhalte &auml;ndert, tragen wir die &Auml;nderungen per Code in diese Tabelle ein.<\/p>\n<p>Die beiden Textfelder nennen wir <b>txtEMail<\/b> und <b>txtNewsletteranmeldung<\/b>. Wir f&uuml;gen diese wie in Bild 5 in das Formular ein.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2021_01\/pic_1280_005.png\" alt=\"Ungebundene Felder f&uuml;r die Metadaten\" width=\"599,593\" height=\"363,7029\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 5: Ungebundene Felder f&uuml;r die Metadaten<\/span><\/b><\/p>\n<h2>Meta-Attributnamen in die Marke-Eigenschaft schreiben<\/h2>\n<p>F&uuml;r sp&auml;ter tragen wir f&uuml;r die beiden Textfelder <b>txtEMail <\/b>und <b>txtNewsletteranmeldung <\/b>die jeweiligen Attributnamen in die Eigenschaft <b>Marke <\/b>ein, die Sie auf der Registerseite <b>Andere <\/b>des Eigenschaftenblatts finden.<\/p>\n<p>Diese ben&ouml;tigen wir sp&auml;ter f&uuml;r die VBA-Programmierung.<\/p>\n<h2>Anzeigen der Daten aus der Metadaten-Tabelle<\/h2>\n<p>Damit die Felder beim Anzeigen eines neuen Datensatzes gef&uuml;llt werden, hinterlegen wir eine Ereignisprozedur f&uuml;r das Ereignis <b>Beim Anzeigen<\/b>. Diese enth&auml;lt zwei Anweisungen. Die erste verwendet die <b>DLookup<\/b>-Funktion, um den Wert des Feldes <b>Attributwert <\/b>des Datensatzes der Tabelle <b>tblKundenMeta <\/b>zu ermitteln, f&uuml;r den das Feld <b>KundeID <\/b>dem aktuellen Kunden und das Feld <b>Attributname <\/b>dem gesuchten Attribut entspricht (siehe Listing 1).<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_Current()\r\n     Me!txtEMail = Nz(DLookup(\"Attributwert\", \"tblKundenMeta\", \"KundeID = \" & Nz(Me!KundeID, 0) _\r\n         & \" AND Attributname = 'E-Mail'\"), \"\")\r\n     Me!txtNewsletteranmeldung = Nz(DLookup(\"Attributwert\", \"tblKundenMeta\", \"KundeID = \" & Nz(Me!KundeID, 0) _\r\n         & \" AND Attributname = 'Newsletteranmeldung'\"), \"\")\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 1: Einlesen der Metadaten und Schreiben in die Textfelder<\/span><\/b><\/p>\n<p>Es kann vorkommen, dass gar nicht alle gesuchten Attribute in der Tabelle <b>tblKundenMeta <\/b>vorhanden sind. Daher fassen wir das Ergebnis der <b>DLookup<\/b>-Funktion noch in die <b>Nz<\/b>-Funktion ein, die eine leere Zeichenkette zur&uuml;ckliefert, wenn kein passender Datensatz gefunden werden konnte.<\/p>\n<p>Schlie&szlig;lich wird dieser Prozedur auch aufgerufen, wenn das Formular einen neuen, leeren Datensatz anzeigt. In diesem Fall ist das Feld <b>KundeID <\/b>noch leer. Also fassen wir auch dieses mit der <b>Nz<\/b>-Funktion ein und liefern den Wert <b>0 <\/b>zur&uuml;ck, wenn <b>KundeID <\/b>den Wert <b>Null <\/b>hat. Die zur&uuml;ckgelieferten Zeichenketten landen in jedem Fall in den beiden Feldern <b>txtEMail <\/b>und <b>txtNewsletterAngemeldet<\/b> (siehe Bild 6).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2021_01\/pic_1280_006.png\" alt=\"Die unteren beiden Textfelder enthalten Metadaten aus der verkn&uuml;pften Tabelle tblKundenMeta.\" width=\"424,7115\" height=\"364,0385\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 6: Die unteren beiden Textfelder enthalten Metadaten aus der verkn&uuml;pften Tabelle tblKundenMeta.<\/span><\/b><\/p>\n<h2>&Auml;ndern der Metadaten<\/h2>\n<p>Nun wollen wir sicherstellen, dass &Auml;nderungen an den Daten der beiden Textfelder <b>txtEMail <\/b>und <b>txtNewsletteranmeldung <\/b>auch in der Tabelle <b>tblKundenMeta <\/b>landen.<\/p>\n<p>Das soll erst dann geschehen, wenn auch die Daten aus den &uuml;brigen Textfeldern gespeichert werden, also beim Speichern des Datensatzes. Dazu eignen sich die beiden Ereignisse <b>Vor Aktualisierung <\/b>und <b>Nach Aktualisierung <\/b>des Formulars.<\/p>\n<p>Wir verwenden <b>Nach Aktualisierung<\/b>, weil der Datensatz der Tabelle <b>tblKunden <\/b>zum Zeitpunkt des Ausl&ouml;sens des Ereignisses <b>Vor Aktualisierung <\/b>noch nicht gespeichert ist (siehe Listing 2). Dann haben wir auch noch keinen Prim&auml;rschl&uuml;sselwert eines neuen Datensatzes der Tabelle <b>tblKunden <\/b>und k&ouml;nnen folglich auch keine damit verkn&uuml;pften Datens&auml;tze in der Tabelle <b>tblKundenMeta <\/b>anlegen.<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_AfterUpdate()\r\n     <span style=\"color:blue;\">Dim <\/span>db<span style=\"color:blue;\"> As <\/span>DAO.Database\r\n     <span style=\"color:blue;\">Dim <\/span>lngKundeMetaID<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Set<\/span> db = CurrentDb\r\n     lngKundeMetaID = Nz(DLookup(\"KundeMetaID\", \"tblKundenMeta\", \"KundeID = \" & Me!KundeID _\r\n         & \" AND Attributname = 'E-Mail'\"), 0)\r\n     <span style=\"color:blue;\">If <\/span>lngKundeMetaID = 0<span style=\"color:blue;\"> Then<\/span>\r\n         db.Execute \"INSERT INTO tblKundenMeta(KundeID, Attributname, Attributwert) VALUES(\" & Me!KundeID _\r\n             & \", 'E-Mail', '\" & Me!txtEMail & \"')\", dbFailOnError\r\n     <span style=\"color:blue;\">Else<\/span>\r\n         db.Execute \"UPDATE tblKundenMeta SET Attributwert = '\" & Me!txtEMail & \"' WHERE KundeID = \" & Me!KundeID _\r\n             & \" AND Attributname = 'E-Mail'\", dbFailOnError\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     lngKundeMetaID = Nz(DLookup(\"KundeMetaID\", \"tblKundenMeta\", \"KundeID = \" & Me!KundeID _\r\n         & \" AND Attributname = 'Newsletteranmeldung'\"), 0)\r\n     <span style=\"color:blue;\">If <\/span>lngKundeMetaID = 0<span style=\"color:blue;\"> Then<\/span>\r\n         db.Execute \"INSERT INTO tblKundenMeta(KundeID, Attributname, Attributwert) VALUES(\" & Me!KundeID _\r\n             & \", 'Newsletteranmeldung', '\" & Me!txtNewsletteranmeldung & \"')\", dbFailOnError\r\n     <span style=\"color:blue;\">Else<\/span>\r\n         db.Execute \"UPDATE tblKundenMeta SET Attributwert = '\" & Me!txtNewsletteranmeldung & \"' WHERE KundeID = \" _\r\n             & Me!KundeID & \" AND Attributname = 'Newsletteranmeldung'\", dbFailOnError\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 2: Schreiben der Metadaten<\/span><\/b><\/p>\n<p>In der Prozedur pr&uuml;fen wir zun&auml;chst, ob es bereits einen Datensatz in der Tabelle <b>tblKundenMeta <\/b>gibt, der zum aktuellen Kunden geh&ouml;rt und das betroffene Attribut enth&auml;lt.<\/p>\n<p>Falls ja, landet der Prim&auml;rschl&uuml;sselwert dieses Datensatzes der Tabelle <b>tblKundenMeta <\/b>in der Variablen <b>lngKundeMetaID<\/b>, anderenfalls der Wert <b>0<\/b>.<\/p>\n<p>Hat <b>lngKundeMetaID <\/b>danach den Wert <b>0<\/b>, legen wir mit einer <b>INSERT INTO<\/b>-Abfrage einen neuen Datensatz in der Tabelle <b>tblKundenMeta <\/b>an, der das Attribut mit dem Wert aus dem Textfeld enth&auml;lt. Falls nicht, aktualisieren wir den vorhandenen Datensatz f&uuml;r den Kunden und das Attribut mit einer <b>UPDATE<\/b>-Abfrage.<\/p>\n<p>Das erledigen wir zuerst f&uuml;r das Feld <b>txtEMail <\/b>und dann f&uuml;r das Feld <b>Newsletteranmeldung<\/b>. Der Code ist recht redundant und kann ausgelagert und parametrisiert werden &#8211; dazu sp&auml;ter mehr.<\/p>\n<p><!--30percent--><\/p>\n<p>Zun&auml;chst pr&uuml;fen wir, ob die Prozedur wie gew&uuml;nscht funktioniert. Dazu legen wir einen neuen Datensatz an und speichern diesen dann beispielsweise durch den Wechseln zum n&auml;chsten neuen Datensatz, zum vorherigen Datensatz oder einfach durch Bet&auml;tigen der Tastenkombination <b>Strg + S<\/b>.<\/p>\n<p>Das funktioniert wie gew&uuml;nscht &#8211; die Daten aus den beiden Textfeldern <b>txtEMail <\/b>und <b>txtNewsletteranmeldung <\/b>landen in zwei neuen Datens&auml;tzen der Tabelle <b>tblKundenMeta<\/b>.<\/p>\n<h2>Kein Speichern ohne &#8222;dreckigen&#8220; Datensatz<\/h2>\n<p>Nun probierern wir uns an einem vorhandenen Datensatz und &auml;ndern ein oder mehrere der gebundenen Felder sowie die beiden Textfelder <b>txtEMail <\/b>und <b>txtNewsletteranmeldung<\/b>. Auch das gelingt: Die ge&auml;nderten Daten der beiden ungebundenen Textfelder landen in den entsprechenden Datens&auml;tzen der Tabelle <b>tblKundenMeta<\/b>.<\/p>\n<p>Wenn wir allerdings nur die Daten von <b>txtEMail <\/b>und\/oder <b>txtNewsletteranmeldung <\/b>&auml;ndern, werden die &Auml;nderungen nicht &uuml;bernommen. Der Grund ist, dass wir den Datensatz nur durch das &Auml;ndern der ungebundenen Textfelder nicht in den bearbeiteten Zustand versetzen und somit auch das Ereignis <b>Nach Aktualisierung <\/b>beim Verlassen des Datensatzes nicht ausgel&ouml;st wird.<\/p>\n<p>Wir m&uuml;ssen also irgendwie daf&uuml;r sorgen, dass die Eigenschaft <b>Dirty <\/b>des Formulars den Wert <b>True <\/b>erh&auml;lt, dass der Datensatz also als &#8222;dreckig&#8220; markiert wird. Das wollen wir erledigen, sobald der Benutzer eine &Auml;nderung in einem der beiden Textfelder <b>txtEMail <\/b>oder <b>txtNewsletteranmeldung <\/b>vorgenommen hat. Wir dachten, das w&auml;re mit den folgenden beiden Prozedur schnell erledigt:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>txtEMail_Change()\r\n     Me.Dirty = <span style=\"color:blue;\">True<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span>\r\n<span style=\"color:blue;\">Private Sub <\/span>txtNewsletteranmeldung_Change()\r\n     Me.Dirty = <span style=\"color:blue;\">True<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Allerdings l&ouml;sen wir damit nur den Fehler aus Bild 7 aus. Wir m&uuml;ssen also den Fokus auf eines der gebundenen Steuerelemente setzen, um den Datensatz als bearbeitet zu markieren. Wie erledigen wir das, ohne das der Benutzer es mitbekommt<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2021_01\/pic_1280_007.png\" alt=\"Die Dirty-Eigenschaft l&auml;sst sich nur setzen, wenn ein gebundenes Feld den Fokus hat.\" width=\"499,6607\" height=\"283,6212\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 7: Die Dirty-Eigenschaft l&auml;sst sich nur setzen, wenn ein gebundenes Feld den Fokus hat.<\/span><\/b><\/p>\n<p>Dazu erweitern wir die durch das Ereignis <b>Bei &Auml;nderung <\/b>ausgel&ouml;sten Ereignisprozeduren wie folgt:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>txtEMail_Change()\r\n     <span style=\"color:blue;\">Dim <\/span>intSelStart<span style=\"color:blue;\"> As Integer<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>intSelLength<span style=\"color:blue;\"> As Integer<\/span>\r\n     intSelStart = Me!txtEMail.SelStart\r\n     intSelLength = Me!txtEMail.SelLength\r\n     Me!Firma.SetFocus\r\n     Me.Dirty = <span style=\"color:blue;\">True<\/span>\r\n     Me!txtEMail.SetFocus\r\n     Me!txtEMail.SelStart = intSelStart\r\n     Me!txtEMail.SelLength = intSelLength\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Wir speichern also die aktuelle Position der Einf&uuml;gemarke und die Gr&ouml;&szlig;e der Markierung in den beiden Variablen <b>intSelStart <\/b>und <b>intSelLength<\/b>. Dann verschieben wir den Fokus auf das gebundene Feld <b>Firma<\/b>, markieren den Datensatz mit <b>Me.Dirty = True <\/b>als bearbeitet und verschieben den Fokus wieder zur&uuml;ck auf das ungebundene Textfeld <b>txtEMail<\/b>.<\/p>\n<p>Au&szlig;erdem stellen wir die Markierung wieder her, indem wir die Eigenschaften <b>SelStart <\/b>und <b>SelLength <\/b>auf die in den Variablen <b>intSelStart <\/b>und <b>intSelLength <\/b>gespeicherten Werte zur&uuml;cksetzen.<\/p>\n<p>Damit gelingt nun auch das Speichern der neuen Werte in den beiden Textfeldern <b>txtEMail <\/b>und <b>txtNewsletteranmeldung<\/b>, ohne dass wir gebundene Felder des Datensatzes bearbeiten m&uuml;ssen &#8211; vorausgesetzt, Sie haben auch f&uuml;r das Ereignis <b>Bei &Auml;nderung <\/b>des Textfeldes <b>txtNewsletteranmeldung <\/b>eine entsprechende Prozedur hinterlegt (siehe Listing 3).<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>txtNewsletteranmeldung_KeyDown(KeyCode<span style=\"color:blue;\"> As Integer<\/span>, Shift<span style=\"color:blue;\"> As Integer<\/span>)\r\n     <span style=\"color:blue;\">Dim <\/span>strAlt<span style=\"color:blue;\"> As String<\/span>\r\n     Select Case KeyCode\r\n         <span style=\"color:blue;\">Case <\/span>vbKeyEscape\r\n             strAlt = Nz(DLookup(\"Attributwert\", \"tblKundenmeta\", \"KundeID = \" & Nz(Me!KundeID, 0) _\r\n                 & \" AND Attributname = 'Newsletteranmeldung'\"), \"\")\r\n             <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> Me!txtNewsletteranmeldung.Value = strAlt<span style=\"color:blue;\"> Then<\/span>\r\n                 Me!txtNewsletteranmeldung = strAlt\r\n                 <span style=\"color:blue;\">If <\/span>GebundeneFelderBearbeitet Or MetaFelderBearbeitet(Me.txtNewsletteranmeldung)<span style=\"color:blue;\"> Then<\/span>\r\n                     KeyCode = 0\r\n                 <span style=\"color:blue;\">End If<\/span>\r\n             <span style=\"color:blue;\">Else<\/span>\r\n                 MetafelderZuruecksetzen\r\n             <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">End Select<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 3: R&uuml;ckg&auml;ngigmachen von &Auml;nderungen<\/span><\/b><\/p>\n<h2>Undo f&uuml;r ungebundene Textfelder<\/h2>\n<p>Um das Verhalten gebundener Textfelder noch genauer abzubilden, fehlt noch die M&ouml;glichkeit, die noch nicht gespeicherten &Auml;nderungen in den Textfeldern durch Bet&auml;tigen der <b>Esc<\/b>-Taste r&uuml;ckg&auml;ngig zu machen.<\/p>\n<p>Dazu fangen wir das Bet&auml;tigen der <b>Esc<\/b>-Taste ab, wenn eines der ungebundenen Textfelder den Fokus hat. Das erledigen wir mit einer Prozedur, die durch das Ereignis <b>Bei Taste ab <\/b>ausgel&ouml;st wird.<\/p>\n<p>Den Parameter <b>KeyCode<\/b>, der einen Zahlenwert f&uuml;r die gedr&uuml;ckte Taste liefert, pr&uuml;fen wir dabei in einer <b>Select Case<\/b>-Bedingung. Hat <b>KeyCode <\/b>den Wert <b>vbKeyEscape<\/b>, lesen wir den zuletzt gespeicherten Wert f&uuml;r dieses Attribut in die Variable <b>strAlt <\/b>ein. Dann vergleichen wir diesen mit dem aktuellen Wert des jeweiligen Textfeldes. Sind die Werte nicht gleich, f&uuml;gen wir den alten Wert wieder in das Textfeld ein.<\/p>\n<p>Nun m&uuml;ssen wir noch entscheiden, ob wir die urspr&uuml;nglich gedr&uuml;ckte Taste, n&auml;mlich die <b>Esc<\/b>-Taste, an das System weiterleiten, damit seine eigentliche Funktion ausgef&uuml;hrt werden kann. Dieses lautet eben, &Auml;nderungen noch nicht gespeicherter Felder oder Datens&auml;tze zu verwerfen, und zwar in zwei Stufen &#8211; zun&auml;chst f&uuml;r das aktuelle Feld und dann, falls noch nicht gespeicherte &Auml;nderungen in anderen gebundenen Feldern vorliegen, auch f&uuml;r den kompletten Datensatz. Bei uns gibt es nun zwei F&auml;lle:<\/p>\n<ul>\n<li>Der Benutzer hat nur das ungebundene Feld ge&auml;ndert, wodurch der Datensatz als ge&auml;ndert markiert wird, und m&ouml;chte diese &Auml;nderung verwerfen. Dann soll auch der Datensatz wieder als gespeichert markiert werden.<\/li>\n<li>Der Benutzer hat zuvor den Inhalt mindestens eines anderen Feldes ge&auml;ndert, wodurch der Datensatz als ge&auml;ndert markiert wurde. Dann hat er noch eines der Meta-Felder ge&auml;ndert. Wenn er diese &Auml;nderung mit <b>Esc <\/b>verwirft, soll der Datensatz selbst weiterhin als bearbeitet und noch nicht gespeichert markiert werden.<\/li>\n<\/ul>\n<p>Also f&uuml;gen wir noch eine Bedingung hinzu, die pr&uuml;ft, ob gebundene Felder bearbeitet wurden. Die Pr&uuml;fung erledigen wir mit zwei Funktion namens <b>GebundeneFelderBearbeitet<\/b> und <b>MetaFelderBearbeitet<\/b>.<\/p>\n<p>Die erste namens <b>GebundeneFelderBearbeitet <\/b>pr&uuml;ft, ob eines der gebundenen Felder nicht den Wert enth&auml;lt, den es beim &Ouml;ffnen des Datensatzes hatte:<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>GebundeneFelderBearbeitet()<span style=\"color:blue;\"> As Boolean<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>ctl<span style=\"color:blue;\"> As <\/span>Control\r\n     <span style=\"color:blue;\">Dim <\/span>strControlSource<span style=\"color:blue;\"> As String<\/span>\r\n     For Each ctl In Me.Controls\r\n         strControlSource = \"\"\r\n         On Error Resume <span style=\"color:blue;\">Next<\/span>\r\n         strControlSource = ctl.ControlSource\r\n         <span style=\"color:blue;\">On Error GoTo<\/span> 0\r\n         <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> <span style=\"color:blue;\">Len<\/span>(strControlSource) = 0<span style=\"color:blue;\"> Then<\/span>\r\n             <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> ctl.Value = ctl.OldValue<span style=\"color:blue;\"> Then<\/span>\r\n                 GebundeneFelderBearbeitet = <span style=\"color:blue;\">True<\/span>\r\n                 <span style=\"color:blue;\">Exit Function<\/span>\r\n             <span style=\"color:blue;\">End If<\/span>\r\n         <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">Next<\/span> ctl\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p>Die Prozedur durchl&auml;uft alle Steuerelemente des Formulars und liest den Wert ihrer Eigenschaft <b>ControlSource <\/b>in die Variable <b>strControlSource <\/b>ein. Das geschieht bei deaktivierter Fehlerbehandlung, weil nicht alle Steuerelemente diese Eigenschaft aufweisen. Die Variable <b>strControlSource <\/b>ist also anschlie&szlig;end nur gef&uuml;llt, wenn die Eigenschaft auch vorhanden ist. Und ob ein Steuerelement eines der zu untersuchenden Steuerelemente ist, erkennen wir dann daran, ob <b>strControlSource <\/b>leer ist oder nicht.<\/p>\n<p>Falls nicht, pr&uuml;fen wir innerhalb der folgenden <b>If&#8230;Then<\/b>-Bedingung, ob der aktuelle Wert (<b>Value<\/b>) des Steuerelements mit dem gespeicherten Wert (<b>OldValue<\/b>) &uuml;bereinstimmt. Falls ja, stellt die Funktion ihren R&uuml;ckgabewert auf <b>True <\/b>ein und die Funktion wird verlassen.<\/p>\n<p>In diesem Fall, also wenn mindestens eines der &uuml;brigen gebundenen Steuerelemente bearbeitet wurde, soll <b>KeyCode <\/b>den Wert <b>0 <\/b>erhalten. Wir setzen also nur den Wert dieses Feldes zur&uuml;ck, leiten aber nicht die Bet&auml;tigung der <b>Esc<\/b>-Taste weiter &#8211; dadurch werden nicht die &Auml;nderungen des vollst&auml;ndigen Datensatzes r&uuml;ckg&auml;ngig gemacht.<\/p>\n<p>Die zweite Funktion <b>MetaFelderBearbeitet <\/b>pr&uuml;ft, ob noch ein anderes als das aktuelle ungebundene Feld bereits bearbeitet wurde (siehe Listing 4).<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>MetaFelderBearbeitet(ctlAktiv<span style=\"color:blue;\"> As <\/span>Control)\r\n     <span style=\"color:blue;\">Dim <\/span>ctl<span style=\"color:blue;\"> As <\/span>Control\r\n     <span style=\"color:blue;\">Dim <\/span>txt<span style=\"color:blue;\"> As <\/span>TextBox\r\n     For Each ctl In Me.Controls\r\n         <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> ctl Is ctlAktiv<span style=\"color:blue;\"> Then<\/span>\r\n             <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> <span style=\"color:blue;\">Len<\/span>(ctl.Tag) = 0<span style=\"color:blue;\"> Then<\/span>\r\n                 If <span style=\"color:blue;\">Not<\/span> ctl.Value = Nz(DLookup(\"Attributwert\", \"tblKundenMeta\", \"KundeID = \" & Me!KundeID _\r\n                         & \" AND Attributname = '\" & ctl.Tag & \"'\"), \"\") Then\r\n                     MetaFelderBearbeitet = <span style=\"color:blue;\">True<\/span>\r\n                     <span style=\"color:blue;\">Exit Function<\/span>\r\n                 <span style=\"color:blue;\">End If<\/span>\r\n             <span style=\"color:blue;\">End If<\/span>\r\n         <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">Next<\/span> ctl\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 4: Pr&uuml;fen, ob noch andere Metafelder bearbeitet wurden<\/span><\/b><\/p>\n<p>Damit das ungebundene Feld, welches die Prozedur <b>txtNewsletteranmeldung_KeyDown <\/b>ausl&ouml;st, nicht auch kontrolliert wird, &uuml;bergeben wir einen Verweis darauf mit dem Parameter <b>ctlAktiv<\/b>. Auch hier durchlaufen wir alle Steuerelemente des Formulars in einer <b>For Each<\/b>-Schleife &uuml;ber die <b>Controls<\/b>-Auflistung. Diesmal schlie&szlig;en wir mit der ersten <b>If&#8230;Then<\/b>-Bedingung aus, dass wir das mit <b>ctlAktiv <\/b>gelieferte Steuerelement untersuchen.<\/p>\n<p>Danach pr&uuml;fen wir, ob es sich bei dem Steuerelement aus <b>ctl <\/b>um eines der Textfelder zum Anzeigen der Metadaten handelt. Das ist der Fall, wenn die VBA-Eigenschaft <b>Tag<\/b>, die wir weiter oben &uuml;ber die <b>Marke<\/b>-Eigenschaft der Steuerelemente mit den Attributnamen gef&uuml;llt haben, nicht leer sind. Finden wir so ein ungebundenes Textfeld, pr&uuml;fen wir, ob sein Wert seit dem letzten Speichern ge&auml;ndert wurde.<\/p>\n<p>Dazu vergleichen wir den aktuellen Wert (aus <b>ctl.Value<\/b>) mit dem zuvor gespeicherten Wert, den wir per DLookup ermitteln. In der <b>DLookup<\/b>-Funktion verwenden wir als Parameter den Wert des Prim&auml;rschl&uuml;sselfeldes <b>KundeID <\/b>sowie den Namen des Attributs aus der <b>Tag<\/b>-Eigenschaft.<\/p>\n<p>Entspricht der aktuelle Wert nicht dem gespeicherten Wert, liefert die Funktion <b>MetafelderBearbeitet <\/b>den Wert <b>True <\/b>zur&uuml;ck und die Funktion wird verlassen.<\/p>\n<p>Nur wenn kein Element mit ge&auml;ndertem Inhalt gefunden wird, liefert die Funktion den Standardwert <b>False <\/b>zur&uuml;ck.<\/p>\n<p>Wenn der Wert des beim Bet&auml;tigen der <b>Esc<\/b>-Taste aktiven Steuerelements mit dem zuletzt gespeicherten Wert &uuml;bereinstimmt, ruft die Prozedur <b>txtNewsletteranmeldung_KeyDown <\/b>die Routine <b>MetafelderZuruecksetzen <\/b>auf (siehe Listing 5).<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>MetafelderZuruecksetzen()\r\n     <span style=\"color:blue;\">Dim <\/span>ctl<span style=\"color:blue;\"> As <\/span>Control\r\n     <span style=\"color:blue;\">Dim <\/span>strAlt<span style=\"color:blue;\"> As String<\/span>\r\n     For Each ctl In Me.Controls\r\n         <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> <span style=\"color:blue;\">Len<\/span>(ctl.Tag) = 0<span style=\"color:blue;\"> Then<\/span>\r\n             strAlt = Nz(DLookup(\"Attributwert\", \"tblKundenMeta\", \"KundeID = \" & Me.KundeID & \" AND Attributname = '\" _\r\n                 & ctl.Tag & \"'\"), \"\")\r\n             <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> ctl.Value = strAlt<span style=\"color:blue;\"> Then<\/span>\r\n                 ctl.Value = strAlt\r\n             <span style=\"color:blue;\">End If<\/span>\r\n         <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">Next<\/span> ctl\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 5: Inhalte der Metafelder zur&uuml;cksetzen<\/span><\/b><\/p>\n<p>Diese durchl&auml;uft wiederum alle Steuerelemente zur Anzeige von Metafeldern in einer <b>For Each<\/b>-Schleife. Um ein Steuerelement als eines mit Metafeld zu identifizieren, pr&uuml;ft sie, ob dieses einen Wert in der Eigenschaft <b>Tag <\/b>enth&auml;lt. Falls ja, ermittelt sie per <b>DLookup<\/b>-Funktion den zuletzt gespeicherten Wert des Eintrags der Tabelle <b>tblKundenMeta <\/b>f&uuml;r das in der <b>Tag<\/b>-Eigenschaft angegebene Feld und den Kunden mit dem Prim&auml;rschl&uuml;sselwert aus <b>KundeID<\/b>.<\/p>\n<p>Ist der Wert aus <b>ctl.Value <\/b>ungleich dem aus <b>strAlt<\/b>, wird der Wert auf den Inhalt aus <b>strAlt <\/b>eingestellt.<\/p>\n<h2>Pr&uuml;fen der Metafelder bei Undo von gebundenen Textfeldern<\/h2>\n<p>Leider haben wir damit noch nicht alle F&auml;lle abgedeckt, denn auch beim Verwerfen von &Auml;nderungen in den gebundenen Feldern wollen wir noch ber&uuml;cksichtigen, ob der Benutzer seit dem letzten Speichern des Datensatzes bereits &Auml;nderungen an den ungebundenen Feldern durchgef&uuml;hrt hat.<\/p>\n<p>Wenn der Benutzer also beispielsweise erst ein ungebundenes Steuerelement mit dem Inhalt eines der Metafelder ge&auml;ndert hat und danach ein gebundenes Textfelder &auml;ndert, soll die <b>Escape<\/b>-Taste wie gewohnt funktionieren.<\/p>\n<p>Das hei&szlig;t, dass dann zuerst das ungebundene Textfeld zur&uuml;ckgesetzt werden soll und beim zweiten Bet&auml;tigen von Escape auch alle anderen Steuerelemente &#8211; gebundene wie ungebundene. Dazu hinterlegen wir f&uuml;r die gebundenen Steuerelemente ebenfalls Prozeduren f&uuml;r das Ereignis <b>Bei Taste ab<\/b>. F&uuml;r das Textfeld <b>Firma<\/b> sieht diese wie in Listing 6 aus.<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Firma_KeyDown(KeyCode<span style=\"color:blue;\"> As Integer<\/span>, Shift<span style=\"color:blue;\"> As Integer<\/span>)\r\n     <span style=\"color:blue;\">Dim <\/span>strAlt<span style=\"color:blue;\"> As String<\/span>\r\n     Select Case KeyCode\r\n         <span style=\"color:blue;\">Case <\/span>vbKeyEscape\r\n             <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> (Me!Firma.Text = Me!Firma.OldValue)<span style=\"color:blue;\"> Then<\/span>\r\n                 <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> (Me!Firma.Value = Me!Firma.OldValue)<span style=\"color:blue;\"> Then<\/span>\r\n                     Me!Firma.Undo\r\n                     <span style=\"color:blue;\">If <\/span>MetaFelderBearbeitet(Me!Firma) Or GebundeneFelderBearbeitet<span style=\"color:blue;\"> Then<\/span>\r\n                         Me.Dirty = <span style=\"color:blue;\">True<\/span>\r\n                         KeyCode = 0\r\n                     <span style=\"color:blue;\">End If<\/span>\r\n                 <span style=\"color:blue;\">End If<\/span>\r\n             <span style=\"color:blue;\">Else<\/span>\r\n                 MetafelderZuruecksetzen\r\n             <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">End Select<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 6: Aktion beim Bet&auml;tigen der Esc-Taste f&uuml;r eines der gebundenen Steuerelemente<\/span><\/b><\/p>\n<p>Die Prozedur pr&uuml;ft zun&auml;chst, ob es sich bei der gedr&uuml;ckten Taste um die <b>Esc<\/b>-Taste handelt. In diesem Fall pr&uuml;ft sie zuerst, ob der aktuelle Inhalt des Textfeldes aus der Eigenschaft <b>Text <\/b>mit dem Wert vor dem Speichern &uuml;bereinstimmt. Diesen ermitteln wir f&uuml;r gebundene Textfelder mit der Eigenschaft <b>OldValue<\/b>.<\/p>\n<p>Danach vergleichen wir den Wert der Eigenschaft <b>Value <\/b>mit <b>OldValue<\/b>. Warum vergleichen wir erst <b>Text <\/b>mit <b>OldValue <\/b>und dann noch <b>Value <\/b>mit <b>OldValue<\/b> Weil es sein kann, dass der Benutzer von diesem Steuerelement aus die <b>Esc<\/b>-Taste bet&auml;tigt, direkt nachdem er den Inhalt ge&auml;ndert hat (Vergleich mit <b>Text<\/b>) oder erst nachdem er zwischenzeitlich den Fokus auf ein anderes Steuerelement verschoben hat (Vergleich mit <b>Value<\/b>).<\/p>\n<p>Sind sowohl <b>Text <\/b>als auch <b>Value <\/b>nicht mit <b>OldValue <\/b>identisch, macht die Prozedur zun&auml;chst die &Auml;nderung am Textfeld mit der <b>Undo<\/b>-Methode r&uuml;ckg&auml;ngig. Dann pr&uuml;ft sie, ob noch andere Felder bearbeitet wurden. In diesem Fall wird die Eigenschaft <b>Dirty <\/b>auf den Wert <b>True <\/b>eingestellt, damit der Datensatz im bearbeiteten Zustand bleibt. Au&szlig;erdem erh&auml;lt <b>KeyCode <\/b>den Wert <b>0<\/b>, damit die eigentliche Funktion der <b>Esc<\/b>-Taste nicht ausgef&uuml;hrt wird.<\/p>\n<p>Wenn nur die erste <b>If&#8230;Then<\/b>-Bedingung den Wert <b>True <\/b>liefert, also wenn das beim Bet&auml;tigen der <b>Esc<\/b>-Schaltfl&auml;che aktive Steuerelement zwar ge&auml;ndert ist, aber nicht als letztes Steuerelement den Fokus hatte, wird <b>KeyCode <\/b>nicht auf <b>0<\/b> eingestellt, damit die Werte alle gebundenen Steuerelemente einfach zur&uuml;ckgesetzt werden.<\/p>\n<p>Au&szlig;erdem setzen wir auch die ge&auml;nderten Metafelder mit der Routine <b>MetafelderZuruecksetzen <\/b>zur&uuml;ck, die wir bereits weiter oben beschrieben haben.<\/p>\n<p>Zusammengefasst verarbeiten wir beim Bet&auml;tigen der <b>Esc<\/b>-Taste die folgenden Konstellationen:<\/p>\n<ul>\n<li>Wenn der Benutzer nacheinander zwei oder mehr gebundene Felder &auml;ndert und dann f&uuml;r das zuletzt ge&auml;nderte Feld die <b>Esc<\/b>-Taste bet&auml;tigt, wird die letzte &Auml;nderung verworfen. Bet&auml;tigt er <b>Esc <\/b>dann erneut, werden alle &Auml;nderungen verworfen.<\/li>\n<li>Wenn der Benutzer nacheinander zwei oder mehr gebundene Felder &auml;ndert und dann f&uuml;r ein anderes als f&uuml;r das zuletzt ge&auml;nderte Feld die <b>Esc<\/b>-Taste bet&auml;tigt, werden alle &Auml;nderungen verworfen.<\/li>\n<li>Wenn der Benutzer nacheinander zwei oder mehr Metafelder &auml;ndert und dann f&uuml;r das zuletzt ge&auml;nderte Metafeld die <b>Esc<\/b>-Taste bet&auml;tigt, wird die letzte &Auml;nderung verworfen. Bet&auml;tigt er <b>Esc <\/b>dann erneut, werden alle &Auml;nderungen verworfen.<\/li>\n<li>Wenn der Benutzer nacheinander zwei oder mehr Metafelder &auml;ndert und dann f&uuml;r ein anderes als f&uuml;r das zuletzt ge&auml;nderte Feld die <b>Esc<\/b>-Taste bet&auml;tigt, werden zuerst die &Auml;nderungen des Metafeldes mit dem Fokus verworfen und erst dann die &uuml;brigen. Der Grund ist, dass wir wegen des zwischenzeitlichen Verschieben des Fokus auf das Feld <b>Firma <\/b>zum Einstellen des Formulars auf den bearbeiteten Zustand nicht mehr ermitteln k&ouml;nnen, ob das aktive Metafeld zuletzt ge&auml;ndert wurde oder ein anderes.<\/li>\n<li>Kombinationen aus ge&auml;nderten gebundenen Feldern und Metafeldern werden ebenfalls wie erwartet behandelt.<\/li>\n<\/ul>\n<p>Die hier vorgestellte Vorgehensweise ist eher eine Studie als ein praxiserprobtes Vorgehen. Wenn Sie diesen Ansatz in der Praxis einsetzen wollen, w&uuml;rden Sie zum Beispiel die Ereignisprozeduren nicht f&uuml;r jedes Steuerelement einzeln anlegen, sondern diese in eine Klasse auslagern, die dann f&uuml;r jedes Steuerelement erstellt wird.<\/p>\n<h2>Abfragen von Metadaten <\/h2>\n<p>Eine weitere Aufgabe ist: Wie k&ouml;nnen wir die Daten aus der zus&auml;tzlichen Tabelle mit dem Metadaten gemeinsam mit den Daten aus der Haupttabelle abfragen und so darstellen, als ob sie aus einer einzigen Tabelle stammen<\/p>\n<p>Zur Veranschaulichung finden Sie in Bild 8 die beiden Tabellen mit einige Beispieldaten. Wie k&ouml;nnen wir die beiden Tabellen in einer Abfrage verkn&uuml;pfen, sodass die Werte des Feldes <b>Attributname <\/b>der Tabelle <b>tblKundenMeta <\/b>als Felder angezeigt werden und die Daten aus dem Feld <b>Attributwert <\/b>als deren Werte<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2021_01\/pic_1280_008.png\" alt=\"Diese Daten sollen per Abfrage zusammengef&uuml;hrt werden.\" width=\"649,559\" height=\"255,5909\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 8: Diese Daten sollen per Abfrage zusammengef&uuml;hrt werden.<\/span><\/b><\/p>\n<h2>Vom Wert zur Spalten&uuml;berschrift<\/h2>\n<p>Hier bedarf es eines Tricks. Mit welchem Abfragetyp k&ouml;nnen wir die Inhalte von Feldern als Felder beziehungsweise als Spalten&uuml;berschriften darstellen Mit der Kreuztabellenabfrage. So geht es weiter:<\/p>\n<ul>\n<li>Erstellen einer Kreuztabelle auf Basis der Tabelle <b>tblKundenMeta <\/b>und<\/li>\n<li>Zusammenf&uuml;hren von <b>tblKunden <\/b>und der Kreuztabelle in einer weiteren Abfrage.<\/li>\n<\/ul>\n<p>Die Kreuztabelle erstellen wir wie folgt:<\/p>\n<ul>\n<li>Legen Sie eine neue, leere Tabelle namens <b>qryMetadatenKreuztabelle <\/b>an.<\/li>\n<li>Ziehen Sie die Tabelle <b>tblKundenMeta <\/b>in den Entwurfsbereich.<\/li>\n<li>Ziehen Sie die Felder <b>KundeID<\/b>, <b>Attributname <\/b>und <b>Attributwert <\/b>in das Entwurfsraster.<\/li>\n<li>Wandeln Sie die Abfrage mit dem Ribbon-Befehl <b>Entwurf|Abfrage|Kreuztabelle <\/b>in eine Kreuztabellenabfrage um.<\/li>\n<li>Stellen Sie f&uuml;r das Feld <b>KundeID <\/b>in der Zeile <b>Funktion <\/b>den Wert <b>Gruppierung <\/b>und in der Zeile <b>Kreuztabelle Zeilen&uuml;berschrift <\/b>ein.<\/li>\n<li>Das Feld <b>Attributname <\/b>soll in der Zeile <b>Funktion <\/b>ebenfalls den Wert <b>Gruppierung <\/b>und in der Zeile <b>Kreuztabelle <\/b>den Wert <b>Spalten&uuml;berschrift <\/b>erhalten.<\/li>\n<li>F&uuml;r das Feld <b>Attributwert <\/b>schlie&szlig;lich legen Sie in der Zeile <b>Funktion <\/b>den Wert <b>ErsterWert <\/b>und f&uuml;r <b>Kreuztabelle <\/b>den Wert <b>Wert <\/b>fest.<\/li>\n<\/ul>\n<p>Das Zwischenergebnis sieht in der Entwurfsansicht wie in Bild 9 aus.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2021_01\/pic_1280_009.png\" alt=\"Kreuztabelle f&uuml;r die Metadaten\" width=\"549,6265\" height=\"322,2598\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 9: Kreuztabelle f&uuml;r die Metadaten<\/span><\/b><\/p>\n<p>Wechseln wir nun in die Datenblattansicht der Abfrage, erhalten wir das Ergebnis aus Bild 10. Das sieht sehr gut aus: <b>Kunde<\/b>, <b>E-Mail <\/b>und <b>Newsletteranmeldung <\/b>erscheinen als Spalten&uuml;berschriften und die entsprechenden Werte landen in den Feldern der beiden Datens&auml;tze.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2021_01\/pic_1280_010.png\" alt=\"Ergebnis der Kreuztabelle\" width=\"499,6607\" height=\"147,382\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 10: Ergebnis der Kreuztabelle<\/span><\/b><\/p>\n<p>Damit k&ouml;nnen wir nun in einer weiteren Abfrage die Daten aus der Kundentabelle und aus der Kreuztabellenabfrage zusammenf&uuml;hren:<\/p>\n<ul>\n<li>Erstellen Sie eine weitere neue Abfrage, diesmal namens <b>qryKundenMitMetadaten<\/b>.<\/li>\n<li>Ziehen Sie die Tabelle <b>tblKunden <\/b>und die Abfrage <b>qryMetadatenKreuztabelle <\/b>in den Entwurfsbereich.<\/li>\n<li>Stellen Sie eine Beziehung zwischen den beiden Tabellen her, indem Sie das Feld <b>KundeID <\/b>der Tabelle <b>tblKunden <\/b>auf das gleichnamige Feld der Abfrage <b>qryMetadatenKreuztabelle <\/b>ziehen.<\/li>\n<li>Ziehen Sie alle Felder der Tabelle <b>tblKunden <\/b>sowie die beiden Felder <b>E-Mail <\/b>und <b>Newsletteranmeldung <\/b>in das Entwurfsraster. Das Ergebnis finden Sie in Bild 11.<\/li>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2021_01\/pic_1280_011.png\" alt=\"Zusammenf&uuml;hren von Kundentabelle und den Daten der Kreuztabelle mit den Metadaten\" width=\"700\" height=\"308,7101\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 11: Zusammenf&uuml;hren von Kundentabelle und den Daten der Kreuztabelle mit den Metadaten<\/span><\/b><\/p>\n<\/ul>\n<p>Wechseln Sie in die Datenblattansicht, erhalten Sie genau das gew&uuml;nschte Ergebnis &#8211; eine Abfrage, die alle Felder der Haupt- und der Metatabelle &uuml;bersichtlich anzeigt (siehe Bild 12).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2021_01\/pic_1280_012.png\" alt=\"Daten aus Haupt- und Metatabelle in einer Abfrage\" width=\"700\" height=\"107,3046\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 12: Daten aus Haupt- und Metatabelle in einer Abfrage<\/span><\/b><\/p>\n<p>Klar ist: Die Daten dieser Abfrage k&ouml;nnen wir nur zum Anzeigen verwenden, jedoch nicht zum Bearbeiten. Das erkennen Sie schon daran, dass die Schaltfl&auml;che zum Hinzuf&uuml;gen neuer Datens&auml;tze in der Navigationsleiste deaktiviert ist.<\/p>\n<h2>Zusammenfassung und Ausblick<\/h2>\n<p>Dieser Beitrag beschreibt eine Technik, um zus&auml;tzliche Daten in die Tabelle einer Datenbank aufzunehmen, ohne explizit Felder f&uuml;r diese Daten anzulegen. Die Felder und ihre Werte werden vielmehr als Name-Wert-Paare in einer eigenen Tabelle gespeichert, die dann wiederum per Fremdschl&uuml;sselfeld dem eigentlichen Datensatz zugewiesen werden.<\/p>\n<p>In dieser Tabelle haben wir per zusammengesetztem Index aus dem Name-Feld und dem Fremdschl&uuml;sselfeld daf&uuml;r gesorgt, dass jedes Attribut nur einmal je Datensatz hinzugef&uuml;gt werden kann. Wenn Sie zus&auml;tzliche Metadaten ben&ouml;tigen, von denen Sie mehr als einen f&uuml;r das gleiche Feld eintragen wollen, m&uuml;ssen Sie die Tabelle ohne den zusammengesetzten Index erstellen. Die hier vorgestellten Techniken reichen dann aber nicht aus, um auch beispielsweise mehrere E-Mail-Adressen je Kunde in verschiedenen Feldern auszugeben.<\/p>\n<p>In einem weiteren Beitrag namens <b>Metadaten durchsuchen <\/b>(<b>www.access-im-unternehmen.de\/****<\/b>) schauen wir uns noch an, wie Sie gezielt nach den Daten in den Metafeldern suchen k&ouml;nnen. Das ist nicht gerade trivial &#8211; gerade weil die Felder ja dynamisch hinzugef&uuml;gt werden k&ouml;nnen und man damit nicht einfach Suchfelder f&uuml;r die einzelnen Metafelder hinterlegen kann.<\/p>\n<p>Die L&ouml;sung wird eher in die Richtung gehen, dass man das oder die zu durchsuchenden Metafelder per Kombinationsfeld ausw&auml;hlt und dann den zu suchenden Wert in ein daf&uuml;r vorgesehenes Textfeld eingibt.<\/p>\n<h3>Downloads zu diesem Beitrag<\/h3>\n<p>Enthaltene Beispieldateien:<\/p>\n<p>MetadatenPerZusatztabelle.accdb<\/p>\n<p><a href=\"..\/fileadmin\/beispiele\/F56923F6-7AB7-4A57-867B-2C20C76117B6\/aiu_1280.zip\">Download<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Im Laufe der Zeit k&ouml;nnen sich einen Menge Daten ansammeln, die Sie in Zusammenhang mit Kunden, Produkten oder &auml;hnlichen Entit&auml;ten speichern wollen. Dabei m&ouml;chten Sie vielleicht nicht f&uuml;r jede neue Eigenschaft ein neues Feld anlegen und damit den Tabellenentwurf &auml;ndern. Das gilt umso mehr, wenn eine Anwendung bereits von vielen Kunden genutzt wird. Es gibt jedoch eine Alternative: Sie k&ouml;nnen eine zus&auml;tzliche Tabelle hinzuf&uuml;gen, die in jedem Datensatz eine Eigenschaft mit dem jeweiligen Wert f&uuml;r die Entit&auml;t speichert. Die Frage ist nur: Wie k&ouml;nnen wir diese Daten genauso nutzen, als wenn diese wie &uuml;blich in der gleichen Tabelle wie der Kunde oder das Produkt gespeichert werden<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_uf_show_specific_survey":0,"_uf_disable_surveys":false,"footnotes":""},"categories":[66012021,662021,44000021],"tags":[],"class_list":["post-55001280","post","type-post","status-publish","format-standard","hentry","category-66012021","category-662021","category-Tabellen_und_Datenmodellierung"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v20.9 (Yoast SEO v27.3) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Metadaten per Zusatztabelle verwalten - Access im Unternehmen<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/access-im-unternehmen.de\/Metadaten_per_Zusatztabelle_verwalten\/\" \/>\n<meta property=\"og:locale\" content=\"de_DE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Metadaten per Zusatztabelle verwalten\" \/>\n<meta property=\"og:description\" content=\"Im Laufe der Zeit k&ouml;nnen sich einen Menge Daten ansammeln, die Sie in Zusammenhang mit Kunden, Produkten oder &auml;hnlichen Entit&auml;ten speichern wollen. Dabei m&ouml;chten Sie vielleicht nicht f&uuml;r jede neue Eigenschaft ein neues Feld anlegen und damit den Tabellenentwurf &auml;ndern. Das gilt umso mehr, wenn eine Anwendung bereits von vielen Kunden genutzt wird. Es gibt jedoch eine Alternative: Sie k&ouml;nnen eine zus&auml;tzliche Tabelle hinzuf&uuml;gen, die in jedem Datensatz eine Eigenschaft mit dem jeweiligen Wert f&uuml;r die Entit&auml;t speichert. Die Frage ist nur: Wie k&ouml;nnen wir diese Daten genauso nutzen, als wenn diese wie &uuml;blich in der gleichen Tabelle wie der Kunde oder das Produkt gespeichert werden\" \/>\n<meta property=\"og:url\" content=\"https:\/\/access-im-unternehmen.de\/Metadaten_per_Zusatztabelle_verwalten\/\" \/>\n<meta property=\"og:site_name\" content=\"Access im Unternehmen\" \/>\n<meta property=\"article:published_time\" content=\"2021-02-17T18:40:17+00:00\" \/>\n<meta property=\"og:image\" content=\"http:\/\/vg07.met.vgwort.de\/na\/7c62bf2db1374078a2a10fcff9e352a2\" \/>\n<meta name=\"author\" content=\"Andr\u00e9 Minhorst\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Verfasst von\" \/>\n\t<meta name=\"twitter:data1\" content=\"Andr\u00e9 Minhorst\" \/>\n\t<meta name=\"twitter:label2\" content=\"Gesch\u00e4tzte Lesezeit\" \/>\n\t<meta name=\"twitter:data2\" content=\"26\u00a0Minuten\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Metadaten_per_Zusatztabelle_verwalten\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Metadaten_per_Zusatztabelle_verwalten\\\/\"},\"author\":{\"name\":\"Andr\u00e9 Minhorst\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/person\\\/13395c4bcd7d7963efe33be9c584d93f\"},\"headline\":\"Metadaten per Zusatztabelle verwalten\",\"datePublished\":\"2021-02-17T18:40:17+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Metadaten_per_Zusatztabelle_verwalten\\\/\"},\"wordCount\":4647,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Metadaten_per_Zusatztabelle_verwalten\\\/#primaryimage\"},\"thumbnailUrl\":\"http:\\\/\\\/vg07.met.vgwort.de\\\/na\\\/7c62bf2db1374078a2a10fcff9e352a2\",\"articleSection\":[\"1\\\/2021\",\"2021\",\"Tabellen und Datenmodellierung\"],\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/access-im-unternehmen.de\\\/Metadaten_per_Zusatztabelle_verwalten\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Metadaten_per_Zusatztabelle_verwalten\\\/\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Metadaten_per_Zusatztabelle_verwalten\\\/\",\"name\":\"Metadaten per Zusatztabelle verwalten - Access im Unternehmen\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Metadaten_per_Zusatztabelle_verwalten\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Metadaten_per_Zusatztabelle_verwalten\\\/#primaryimage\"},\"thumbnailUrl\":\"http:\\\/\\\/vg07.met.vgwort.de\\\/na\\\/7c62bf2db1374078a2a10fcff9e352a2\",\"datePublished\":\"2021-02-17T18:40:17+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Metadaten_per_Zusatztabelle_verwalten\\\/#breadcrumb\"},\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/access-im-unternehmen.de\\\/Metadaten_per_Zusatztabelle_verwalten\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Metadaten_per_Zusatztabelle_verwalten\\\/#primaryimage\",\"url\":\"http:\\\/\\\/vg07.met.vgwort.de\\\/na\\\/7c62bf2db1374078a2a10fcff9e352a2\",\"contentUrl\":\"http:\\\/\\\/vg07.met.vgwort.de\\\/na\\\/7c62bf2db1374078a2a10fcff9e352a2\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Metadaten_per_Zusatztabelle_verwalten\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Metadaten per Zusatztabelle verwalten\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#website\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\",\"name\":\"Access im Unternehmen\",\"description\":\"Das Magazin f\u00fcr Datenbankentwickler auf Basis von Microsoft Access\",\"publisher\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/access-im-unternehmen.de\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"de\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\",\"name\":\"Andr\u00e9 Minhorst Verlag\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/wp-content\\\/uploads\\\/2019\\\/09\\\/aiu_wp.png\",\"contentUrl\":\"https:\\\/\\\/access-im-unternehmen.de\\\/wp-content\\\/uploads\\\/2019\\\/09\\\/aiu_wp.png\",\"width\":370,\"height\":111,\"caption\":\"Andr\u00e9 Minhorst Verlag\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/logo\\\/image\\\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/person\\\/13395c4bcd7d7963efe33be9c584d93f\",\"name\":\"Andr\u00e9 Minhorst\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g\",\"caption\":\"Andr\u00e9 Minhorst\"}}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Metadaten per Zusatztabelle verwalten - Access im Unternehmen","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/access-im-unternehmen.de\/Metadaten_per_Zusatztabelle_verwalten\/","og_locale":"de_DE","og_type":"article","og_title":"Metadaten per Zusatztabelle verwalten","og_description":"Im Laufe der Zeit k&ouml;nnen sich einen Menge Daten ansammeln, die Sie in Zusammenhang mit Kunden, Produkten oder &auml;hnlichen Entit&auml;ten speichern wollen. Dabei m&ouml;chten Sie vielleicht nicht f&uuml;r jede neue Eigenschaft ein neues Feld anlegen und damit den Tabellenentwurf &auml;ndern. Das gilt umso mehr, wenn eine Anwendung bereits von vielen Kunden genutzt wird. Es gibt jedoch eine Alternative: Sie k&ouml;nnen eine zus&auml;tzliche Tabelle hinzuf&uuml;gen, die in jedem Datensatz eine Eigenschaft mit dem jeweiligen Wert f&uuml;r die Entit&auml;t speichert. Die Frage ist nur: Wie k&ouml;nnen wir diese Daten genauso nutzen, als wenn diese wie &uuml;blich in der gleichen Tabelle wie der Kunde oder das Produkt gespeichert werden","og_url":"https:\/\/access-im-unternehmen.de\/Metadaten_per_Zusatztabelle_verwalten\/","og_site_name":"Access im Unternehmen","article_published_time":"2021-02-17T18:40:17+00:00","og_image":[{"url":"http:\/\/vg07.met.vgwort.de\/na\/7c62bf2db1374078a2a10fcff9e352a2","type":"","width":"","height":""}],"author":"Andr\u00e9 Minhorst","twitter_card":"summary_large_image","twitter_misc":{"Verfasst von":"Andr\u00e9 Minhorst","Gesch\u00e4tzte Lesezeit":"26\u00a0Minuten"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/access-im-unternehmen.de\/Metadaten_per_Zusatztabelle_verwalten\/#article","isPartOf":{"@id":"https:\/\/access-im-unternehmen.de\/Metadaten_per_Zusatztabelle_verwalten\/"},"author":{"name":"Andr\u00e9 Minhorst","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/person\/13395c4bcd7d7963efe33be9c584d93f"},"headline":"Metadaten per Zusatztabelle verwalten","datePublished":"2021-02-17T18:40:17+00:00","mainEntityOfPage":{"@id":"https:\/\/access-im-unternehmen.de\/Metadaten_per_Zusatztabelle_verwalten\/"},"wordCount":4647,"commentCount":0,"publisher":{"@id":"https:\/\/access-im-unternehmen.de\/#organization"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/Metadaten_per_Zusatztabelle_verwalten\/#primaryimage"},"thumbnailUrl":"http:\/\/vg07.met.vgwort.de\/na\/7c62bf2db1374078a2a10fcff9e352a2","articleSection":["1\/2021","2021","Tabellen und Datenmodellierung"],"inLanguage":"de","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/access-im-unternehmen.de\/Metadaten_per_Zusatztabelle_verwalten\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/access-im-unternehmen.de\/Metadaten_per_Zusatztabelle_verwalten\/","url":"https:\/\/access-im-unternehmen.de\/Metadaten_per_Zusatztabelle_verwalten\/","name":"Metadaten per Zusatztabelle verwalten - Access im Unternehmen","isPartOf":{"@id":"https:\/\/access-im-unternehmen.de\/#website"},"primaryImageOfPage":{"@id":"https:\/\/access-im-unternehmen.de\/Metadaten_per_Zusatztabelle_verwalten\/#primaryimage"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/Metadaten_per_Zusatztabelle_verwalten\/#primaryimage"},"thumbnailUrl":"http:\/\/vg07.met.vgwort.de\/na\/7c62bf2db1374078a2a10fcff9e352a2","datePublished":"2021-02-17T18:40:17+00:00","breadcrumb":{"@id":"https:\/\/access-im-unternehmen.de\/Metadaten_per_Zusatztabelle_verwalten\/#breadcrumb"},"inLanguage":"de","potentialAction":[{"@type":"ReadAction","target":["https:\/\/access-im-unternehmen.de\/Metadaten_per_Zusatztabelle_verwalten\/"]}]},{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/access-im-unternehmen.de\/Metadaten_per_Zusatztabelle_verwalten\/#primaryimage","url":"http:\/\/vg07.met.vgwort.de\/na\/7c62bf2db1374078a2a10fcff9e352a2","contentUrl":"http:\/\/vg07.met.vgwort.de\/na\/7c62bf2db1374078a2a10fcff9e352a2"},{"@type":"BreadcrumbList","@id":"https:\/\/access-im-unternehmen.de\/Metadaten_per_Zusatztabelle_verwalten\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/access-im-unternehmen.de\/"},{"@type":"ListItem","position":2,"name":"Metadaten per Zusatztabelle verwalten"}]},{"@type":"WebSite","@id":"https:\/\/access-im-unternehmen.de\/#website","url":"https:\/\/access-im-unternehmen.de\/","name":"Access im Unternehmen","description":"Das Magazin f\u00fcr Datenbankentwickler auf Basis von Microsoft Access","publisher":{"@id":"https:\/\/access-im-unternehmen.de\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/access-im-unternehmen.de\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"de"},{"@type":"Organization","@id":"https:\/\/access-im-unternehmen.de\/#organization","name":"Andr\u00e9 Minhorst Verlag","url":"https:\/\/access-im-unternehmen.de\/","logo":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/logo\/image\/","url":"https:\/\/access-im-unternehmen.de\/wp-content\/uploads\/2019\/09\/aiu_wp.png","contentUrl":"https:\/\/access-im-unternehmen.de\/wp-content\/uploads\/2019\/09\/aiu_wp.png","width":370,"height":111,"caption":"Andr\u00e9 Minhorst Verlag"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/person\/13395c4bcd7d7963efe33be9c584d93f","name":"Andr\u00e9 Minhorst","image":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/secure.gravatar.com\/avatar\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g","caption":"Andr\u00e9 Minhorst"}}]}},"_links":{"self":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts\/55001280","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/comments?post=55001280"}],"version-history":[{"count":0,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts\/55001280\/revisions"}],"wp:attachment":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/media?parent=55001280"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/categories?post=55001280"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/tags?post=55001280"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}