{"id":55001220,"date":"2020-02-01T00:00:00","date_gmt":"2020-07-10T09:39:29","guid":{"rendered":"http:\/\/access-im-unternehmen.aix-dev.de\/aiu\/?p=1220"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-30T00:00:00","slug":"Optionen_und_andere_Daten_updatesicher_speichern","status":"publish","type":"post","link":"https:\/\/access-im-unternehmen.de\/Optionen_und_andere_Daten_updatesicher_speichern\/","title":{"rendered":"Optionen und andere Daten updatesicher speichern"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/vg06.met.vgwort.de\/na\/c57e4e609dd7412b908182db6c4e6fde\" width=\"1\" height=\"1\" alt=\"\"><\/p>\n<p><b>Wenn mehrere Benutzer &uuml;ber Frontend-Anwendungen an verschiedenen Arbeitspl&auml;tzen auf die Daten einer Backend-Datenbank zugreifen, ist das kein Problem. In vielen Anwendungen ist es dabei sinnvoll, die M&ouml;glichkeit zum Speichern von Optionen je Benutzer vorzusehen. Oft legt man dabei eine Tabelle namens &#8222;tblOptionen&#8220; im Frontend an. Das ist aber nur sinnvoll, wenn auch immer der gleiche Benutzer am gleichen Frontend arbeitet &#8211; anderenfalls w&uuml;rde er ja die Optionen eines anderen Benutzers vorgesetzt bekommen. Oder Sie f&uuml;hren ein Update des Frontends durch &#8211; auch dann w&auml;ren die Optionen des Benutzers nicht mehr vorhanden. Welche Alternativen dazu gibt es Sie k&ouml;nnten zum Beispiel die Optionen in einer Tabelle im Backend speichern und diese beim Anmelden des Benutzers auslesen und in eine lokale Optionentabelle &uuml;bertragen. Oder Sie f&uuml;gen dem Frontend ein  lokales Backend hinzu, das nur die Daten enth&auml;lt, die beim Update des Frontends nicht &uuml;berschrieben werden sollen. Wie das gelingt, zeigen wir im vorliegenden Artikel.<\/b><\/p>\n<p>Am einfachsten ist das Speichern der Optionen eines Benutzers im Frontend. Und auch wenn wir das schon so in fr&uuml;heren Beitr&auml;gen propagiert haben: Die L&ouml;sung ist nur unter ganz bestimmten Rahmenbedingungen pragmatisch. Die folgenden Bedingungen w&uuml;rden es erlauben, die Optionen einfach in einer Tabelle namens <b>tblOptionen <\/b>im Frontend zu speichern:<\/p>\n<ul>\n<li>Am Rechner mit dem Frontend arbeitet immer nur der Mitarbeiter, dessen Optionen in der Tabelle <b>tblOptionen <\/b>dieses Frontends gespeichert sind.<\/li>\n<li>Es gibt keine Updates f&uuml;r das Frontend. Sonst w&uuml;rden mit einem Update, das durch einfaches Ersetzen &uuml;ber die vorhandene Version kopiert wird, immer die bestehenden Optionswerte gel&ouml;scht werden.<\/li>\n<\/ul>\n<p>Es kann sein, dass beide Bedingungen erf&uuml;llt werden. Gerade wenn ein Frontend auf einem Notebook l&auml;uft, das einem Mitarbeiter fest zugeteilt ist, wird sich dort kaum ein anderer Mitarbeiter anmelden und die Access-Anwendung nutzen, der seinen eigenen Satz von Optionen erwartet. Und es gibt sicher auch Anwendungen, die bereits fertig programmiert sind und keinerlei Erweiterungen oder &Auml;nderungen mehr ben&ouml;tigen, sodass es schlicht und einfach keine Updates mehr zu diesen Anwendungen gibt.<\/p>\n<p>Tats&auml;chlich ist aber nicht sichergestellt, dass Microsoft nicht einmal einen Fehler in ein Update integriert, der die &uuml;bliche Funktion von Access verhindert &#8211; und dann kann es gegebenenfalls doch einmal n&ouml;tig sein, dass ein Update &uuml;ber die aktuelle Version mit den gespeicherten Optionen des Benutzers kopiert werden muss (tats&auml;chlich ist genau das vor kurzem geschehen &#8211; pl&ouml;tzlich funktionierten n&auml;mlich Abfragen nicht mehr fehlerfrei, was sich entweder kurzfristig durch eine &Auml;nderung der Programmierung beheben lie&szlig; oder durch das Warten auf das n&auml;chste Update oder den Bugfix von Microsoft).<\/p>\n<p>Wir gehen in diesem Beitrag zun&auml;chst davon aus, dass jeder Benutzer seinen eigenen Rechner hat und wir die Optionentabelle einfach in einem lokalen Backend anlegen. Sp&auml;ter schauen wir uns an, wie die L&ouml;sung f&uuml;r das Speichern der Optionen aller Benutzer im Backend auf dem Server aussehen kann.<\/p>\n<p><b>Die Optionentabelle<\/b><\/p>\n<p>Die Optionentabelle kann unterschiedlich aufgebaut sein. Die erste M&ouml;glichkeit ist, die Optionentabelle so zu gestalten, dass jede Option fest als Feld vorgesehen ist. Das sieht dann etwa wie in Bild 1 aus. Diese Variante hat den Vorteil, dass man f&uuml;r jede Option den Felddatentyp individuell festlegen kann &#8211; so, wie wir es hier auch gemacht haben. <\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2020_01\/pic_1220_001.png\" alt=\"Optionstabelle mit je einem Feld pro Option\" width=\"499,6607\" height=\"379,3045\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 1: Optionstabelle mit je einem Feld pro Option<\/span><\/b><\/p>\n<p>In dieser Variante braucht man eigentlich kein Prim&auml;rschl&uuml;sselfeld, denn es gibt ja zumindest in einer Anwendung f&uuml;r nur einen Arbeitsplatz auch nur einen Datensatz mit Optionen. Da wir aber auch davon ausgehen m&uuml;ssen, dass einmal die Optionen f&uuml;r mehr als einen Anwender gespeichert werden m&uuml;ssen, haben wir vorsichtshalber schon einmal ein Prim&auml;rschl&uuml;sselfeld hinzugef&uuml;gt.<\/p>\n<p>Die Alternative ist, f&uuml;r jede Option einen eigenen Datensatz anzulegen, der dann in einem Feld den Namen der Option enth&auml;lt und in einem weiteren Feld den Optionswert. Das sieht im Entwurf wie in Bild 2 aus.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2020_01\/pic_1220_002.png\" alt=\"Optionstabelle mit einer Option je Datensatz\" width=\"499,6607\" height=\"363,804\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 2: Optionstabelle mit einer Option je Datensatz<\/span><\/b><\/p>\n<p>Der Vorteil dieser Variante ist, dass Sie f&uuml;r das Anlegen neuer Optionen nicht in den Entwurf des Datenmodells eingreifen m&uuml;ssen, sondern nur einen neuen Datensatz hinzuzuf&uuml;gen brauchen. Der Nachteil ist, dass wir ausschlie&szlig;lich Werte eines zuvor festzulegenden Datentyps als Optionswerte festlegen k&ouml;nnen. Dieser Nachteil ist aber nicht allzu gewichtig, denn wir k&ouml;nnen ja alle Datentypen auch im Textformat speichern und gegebenenfalls in den ben&ouml;tigten Datentyp umwandeln.<\/p>\n<p><b>Optionentabelle im lokalen Backend<\/b><\/p>\n<p>Wenn wir die Optionen updatesicher speichern wollen, m&uuml;ssen wir diese au&szlig;erhalb des Frontends unterbringen. Updatesicher speichern bedeutet dabei, dass wir sicherstellen wollen, dass wir das Frontend durch eine neue Version ersetzen k&ouml;nnen, ohne dass die f&uuml;r den Benutzer der Anwendung gespeicherten Optionen verloren gehen. Das erledigen wir, indem wir die Optionentabelle in eine eigene Backenddatenbank auslagern, die wir dann im gleichen Verzeichnis wie die Frontendanwendung speichern. Wir f&uuml;gen dem Frontend dann eine Verkn&uuml;pfung zu dieser Tabelle hinzu, die automatisch beim &Ouml;ffnen der Frontendanwendung gepr&uuml;ft und erneuert wird.<\/p>\n<p><b>Verkn&uuml;pfung beim Start aktualisieren<\/b><\/p>\n<p>Die Aktualisierung der Verkn&uuml;pfung zur Optionentabelle erledigen wir direkt beim Start der Anwendung. Dazu gibt es verschiedene M&ouml;glichkeiten, wo wir den Aufruf des dazu notwendigen VBA-Code platzieren:<\/p>\n<ul>\n<li>Im <b>Load<\/b>&#8211; oder <b>Open<\/b>-Ereignis eines Formulars, das automatisch beim Starten der Frontendanwendung angezeigt wird, oder<\/li>\n<li>in einer VBA-Prozedur, die durch die Makroaktion <b>Ausf&uuml;hrenCode <\/b>im automatisch beim Start ausgef&uuml;hrten <b>AutoExec<\/b>-Makro aufgerufen wird.<\/li>\n<\/ul>\n<p>Wir gehen an dieser Stelle davon aus, dass Sie bereits eine Frontendanwendung vorliegen haben und eine Backenddatenbank, welche die Optionentabelle enth&auml;lt. Was kann bei der Verkn&uuml;pfung alles geschehen und den Vorgang blockieren<\/p>\n<ul>\n<li>Die Verkn&uuml;pfung in der Frontenddatenbank ist vorhanden, aber verweist auf die falsche oder eine nicht vorhandene Tabelle.<\/li>\n<li>Die Verkn&uuml;pfung in der Frontenddatenbank ist nicht vorhanden.<\/li>\n<li>Die Backenddatenbank ist nicht vorhanden.<\/li>\n<li>Die Backenddatenbank ist vorhanden, aber die Optionentabelle ist nicht darin enthalten.<\/li>\n<\/ul>\n<p>Die folgenden Funktionen sollen all dies addressieren, um die in der Konstanten <b>cStrOptionentabelle <\/b>angegebene Tabelle der in der Konstanten <b>cStrOptionenbackend <\/b>angegebenen Datenbank aus dem Verzeichnis des Frontends zu verkn&uuml;pfen.<\/p>\n<p><b>Name von Backend und Tabelle speichern<\/b><\/p>\n<p>Wir m&uuml;ssen an irgendeiner Stelle die Informationen dar&uuml;ber speichern, wie die Datenbankdatei mit der Optionentabelle und wie die darin enthaltene Optionentabelle hei&szlig;t &#8211; was auch dem Namen der Verkn&uuml;pfung f&uuml;r die Optionentabelle in der Frontend-Datenbank entspricht. Dazu legen wir im Modul <b>mdlBackendoptionen<\/b>, dem wir nachfolgend die Funktionen zum Pr&uuml;fen und Wiederherstellen der Verkn&uuml;pfung hinzuf&uuml;gen, die folgenden beiden Konstanten mit dem Datentyp <b>String <\/b>an:<\/p>\n<pre>Const cStrOptionenbackend<span style=\"color:blue;\"> As String<\/span> = \"Backend_Optionen.accdb\"\r\nConst cStrOptionentabelle<span style=\"color:blue;\"> As String<\/span> = \"tblOptionen_Felder\"<\/pre>\n<p>Die Backenddatenbank soll also <b>Backend_Op-tio-nen.accdb <\/b>hei&szlig;en, als Backendtabelle mit den Optionen verwenden wir die Tabelle namens <b>tblOptionen_Felder<\/b>.<\/p>\n<p>Wo aber speichern wir den Pfad, in dem sich die Back-end-datenbank befindet Diesen speichern wir gar nicht, denn die Backenddatenbank mit der Optionentabelle soll sich schlicht im gleichen Verzeichnis wie die Frontenddaten-bank befinden. Und diesen ermitteln wir per VBA zur Laufzeit mit der Eigenschaft <b>CurrentProject.Path<\/b>.<\/p>\n<p><b>Pr&uuml;fen, ob die Backenddatenbank vorhanden ist<\/b><\/p>\n<p>Die erste M&ouml;glichkeit f&uuml;r eine Fehlfunktion ist, dass die Backenddatenbank gar nicht an Ort und Stelle ist. Das pr&uuml;fen wir mit einer Funktion namens <b>IstBackendVorhanden<\/b>. Diese stellt in der Variablen <b>strPfad <\/b>den Pfad zum Backend zusammen, der aus dem Verzeichnis der aktuellen Datenbank und dem Datenbanknamen aus der Konstanten <b>cStrOptionenbackend <\/b>besteht.<\/p>\n<p>Mit der <b>Dir<\/b>-Funktion ermitteln wir die erste Datei, die unter dieser Pfadangabe gefunden werden kann. Dies sollte die in <b>cStrOptionenBackend <\/b>angegebene Datei liefern oder, wenn diese Datei nicht gefunden werden kann, eine leere Zeichenkette. Beides landet in der Variablen <b>strBackenddatei<\/b>. Um zu pr&uuml;fen, ob diese Variable nicht leer ist, ermitteln wir die Anzahl der Zeichen des Wertes dieser Variablen. Ist diese gleich <b>0<\/b>, konnte die Datei nicht im angegebenen Verzeichnis gefunden werden und die Funktion liefert den Wert <b>False <\/b>zur&uuml;ck. Wenn die Zeichenkette aus <b>strBackenddatei <\/b>jedoch eine L&auml;nge gr&ouml;&szlig;er als <b>0 <\/b>aufweist, dann ist die Datei vorhanden und die Funktion liefert den Wert <b>True <\/b>zur&uuml;ck:<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>IstBackendVorhanden()<span style=\"color:blue;\"> As Boolean<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strPfad<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strBackenddatei<span style=\"color:blue;\"> As String<\/span>\r\n     strPfad = CurrentProject.Path & \"\"  & cStrOptionenbackend\r\n     strBackenddatei = Dir(strPfad)\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> <span style=\"color:blue;\">Len<\/span>(strBackenddatei) = 0<span style=\"color:blue;\"> Then<\/span>\r\n         IstBackendVorhanden = <span style=\"color:blue;\">True<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b>Pr&uuml;fen, ob die Optionentabelle im Backend vorliegt<\/b><\/p>\n<p>Damit gehen wir einen Schritt weiter, n&auml;mlich zur Pr&uuml;fung des Vorhandenseins der Optionentabelle in der Backenddatenbank. Dazu referenzieren wir die Backenddatenbank und pr&uuml;fen, ob dort ein <b>TableDef<\/b>-Objekt mit dem angegebenen Namen vorhanden ist.<\/p>\n<p>Dazu stellen wir wieder in <b>strPfad<\/b> den Pfad zur Backenddatenbank zusammen. Diesmal pr&uuml;fen wir allerdings nicht, ob diese vorhanden ist, sondern &ouml;ffnen mit der <b>OpenDatabase<\/b>-Methode ein <b>Database<\/b>-Objekt auf Basis dieser Datenbank und speichern dieses in der Variablen <b>db<\/b>. Dann versuchen wir wieder, bei deaktivierter Fehlerbehandlung auf das <b>TableDef<\/b>-Objekt aus <b>cStrOptionenbackend <\/b>zuzugreifen. Ist die damit gef&uuml;llte Variable <b>tdf <\/b>danach nicht leer, ist die Tabelle in der Backenddatenbank enthalten:<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>IstOptionentabelleVorhanden()<span style=\"color:blue;\"> As Boolean<\/span>\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>tdf<span style=\"color:blue;\"> As <\/span>DAO.TableDef\r\n     <span style=\"color:blue;\">Dim <\/span>strPfad<span style=\"color:blue;\"> As String<\/span>\r\n     strPfad = CurrentProject.Path & \"\"  & cStrOptionenbackend\r\n     <span style=\"color:blue;\">Set<\/span> db = OpenDatabase(strPfad)\r\n     On Error Resume <span style=\"color:blue;\">Next<\/span>\r\n     <span style=\"color:blue;\">Set<\/span> tdf = db.TableDefs(cStrOptionentabelle)\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> tdf Is Nothing<span style=\"color:blue;\"> Then<\/span>\r\n         IstOptionentabelleVorhanden = <span style=\"color:blue;\">True<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b>Pr&uuml;fen, ob Verkn&uuml;pfung vorhanden ist<\/b><\/p>\n<p>Die erste Hilfsfunktion pr&uuml;ft, ob die Verkn&uuml;pfung &uuml;berhaupt im Frontend vorhanden ist. Sie hei&szlig;t <b>IstVerknuep-fungVorhanden <\/b>und liefert einen R&uuml;ckgabewert des Typs <b>Boolean<\/b>. Die Funktion erstellt ein Objekt mit einem Verweis auf das <b>Database<\/b>-Objekt der Frontenddatenbank. Dann deaktiviert sie die eingebaute Fehlerbehandlung und versucht, &uuml;ber die <b>TableDefs<\/b>-Auflistung des <b>Database<\/b>-Objekts auf die Tabelle mit dem in <b>cStrOptionenTabelle <\/b>gespeicherten Namen zuzugreifen und einen Verweis darauf mit der Variablen <b>tdf <\/b>zu referenzieren.<\/p>\n<p>Wir pr&uuml;fen danach gar nicht erst, ob dabei ein Fehler aufgetreten ist oder nicht (ein Fehler w&uuml;rde beim Zugriff auf ein nicht vorhandenes <b>TableDef<\/b>-Element ausgel&ouml;st werden), sondern aktivieren danach einfach die Fehlerbehandlung wieder und pr&uuml;fen dann, ob <b>tdf<\/b> mit einem Objektverweis gef&uuml;llt ist. Falls ja, wurde die Verkn&uuml;pfung offensichtlich gefunden, falls nicht, fehlt sie in der aktuellen Datenbank:<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>IstVerknuepfungVorhanden()<span style=\"color:blue;\"> As Boolean<\/span>\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>tdf<span style=\"color:blue;\"> As <\/span>DAO.TableDef\r\n     <span style=\"color:blue;\">Set<\/span> db = CurrentDb\r\n     On Error Resume <span style=\"color:blue;\">Next<\/span>\r\n     <span style=\"color:blue;\">Set<\/span> tdf = db.TableDefs(cStrOptionentabelle)\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> tdf Is Nothing<span style=\"color:blue;\"> Then<\/span>\r\n         IstVerknuepfungVorhanden = <span style=\"color:blue;\">True<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p>Wenn die Verkn&uuml;pfung gar nicht vorhanden ist, m&uuml;ssen wir diese anlegen. Das erledigen wir gleich in der Hauptfunktion, die auch die Funktion <b>IstVerknuepfungVorhanden <\/b>aufruft.<\/p>\n<p><b>Pr&uuml;fen, ob die Verkn&uuml;pfung auf die richtige Tabelle in der richtigen Datenbank verweist<\/b><\/p>\n<p>Es kann auch sein, dass die Verkn&uuml;pfung zwar vorhanden ist, aber nicht auf die richtige Tabelle verweist. Oder dass sie zwar auf die Tabelle mit dem richtigen Namen verweist, diese sich aber nicht in der richtigen Datenbank im richtigen Verzeichnis befindet.<\/p>\n<p>Dies pr&uuml;fen wir beides in der Funktion <b>IstVerknuepfungKorrekt<\/b> (siehe Listing 1). Diese referenziert das <b>TableDefs<\/b>-Objekt aus <b>cStrOptionentabelle <\/b>und schreibt daraus die Inhalte der <b>Connect<\/b>-Eigenschaft in die Variable <b>strConnect <\/b>und der <b>SourceTableName<\/b>-Eigenschaft in die Variable <b>strTabelle<\/b>. Die <b>Connect<\/b>-Eigenschaft liefert einen Ausdruck, der mit <b>;DATABASE= <\/b>beginnt und dann den Pfad zu der Datenbank liefert, in welcher sich die verkn&uuml;pfte Tabelle befindet. Die <b>SourceTableName<\/b>-Eigenschaft enth&auml;lt den Namen der Tabelle in dieser Backenddatenbank.<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>IstVerknuepfungKorrekt()<span style=\"color:blue;\"> As Boolean<\/span>\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>tdf<span style=\"color:blue;\"> As <\/span>DAO.TableDef\r\n     <span style=\"color:blue;\">Dim <\/span>strConnect<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strTabelle<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Set<\/span> db = CurrentDb\r\n     <span style=\"color:blue;\">Set<\/span> tdf = db.TableDefs(cStrOptionentabelle)\r\n     strConnect = tdf.Connect\r\n     strTabelle = tdf.SourceTableName\r\n     <span style=\"color:blue;\">If <\/span>strTabelle = cStrOptionentabelle<span style=\"color:blue;\"> Then<\/span>\r\n         If strConnect = \";DATABASE=\" & CurrentProject.Path & \"\" _\r\n                 & cStrOptionenbackend Then\r\n             IstVerknuepfungKorrekt = <span style=\"color:blue;\">True<\/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 Function<\/span><\/pre>\n<p><!--30percent--><\/p>\n<p><b><span style=\"color:darkgrey;\">Listing 1: Pr&uuml;fen, ob die Verkn&uuml;pfung die richtige Datenbank und Tabelle addressiert<\/span><\/b><\/p>\n<p>Wir pr&uuml;fen zun&auml;chst, ob der Wert in <b>strTabelle <\/b>mit dem Namen aus <b>cStrOptionentabelle <\/b>&uuml;bereinstimmt. Ist das der Fall, untersuchen wir, ob der Wert aus <b>strConnect <\/b>mit der Zeichenkette bestehend aus <b>;DATABASE=<\/b>, dem Verzeichnis der aktuellen Datenbank und dem Datenbanknamen aus <b>cStrOptionenbackend <\/b>besteht. Sind beide Bedingungen erf&uuml;llt, stellen wir den R&uuml;ckgabewert der Funktion auf <b>True <\/b>ein.<\/p>\n<p><b>Prozedur zum Pr&uuml;fen und Korrigieren der Verkn&uuml;pfung <\/b><\/p>\n<p>Mit diesen Hilfsfunktionen k&ouml;nnen wir nun entspannt in die Hauptprozedur einsteigen, die pr&uuml;ft, ob alle Bedingungen erf&uuml;llt sind und gegebenenfalls Korrekturen vornimmt, damit dies der Fall ist. Aber in welcher Reihenfolge pr&uuml;fen wir die Bedingungen und wann und wie greifen wir korrigierend ein <\/p>\n<p>Wir k&ouml;nnen beispielsweise damit einsteigen, dass wir mit der Funktion <b>IstVerknuepfungVorhanden <\/b>pr&uuml;fen, ob die Verkn&uuml;pfung zur Optionentabelle &uuml;berhaupt im Frontend vorliegt. Aber was tun, wenn das schon nicht der Fall ist Sollen wir diese dann einfach anlegen und dann die weiteren Bedingungen pr&uuml;fen Das ist wenig sinnvoll, denn wenn wir nicht wissen, ob die Backenddatenbank &uuml;berhaupt vorhanden ist, brauchen wir auch nicht die Verkn&uuml;pfung zu reparieren. Also starten wir in der ersten Version der Funktion <b>OptionentabelleVerknuepfen <\/b>bei den wesentlichen Voraussetzungen (siehe Listing 2). Die Erste lautet: Ist die Backenddatenbank &uuml;berhaupt an Ort und Stelle Das pr&uuml;fen wir mit der Funktion <b>IstBackendVorhanden<\/b>. Falls ja, gehen wir mit der Pr&uuml;fung der n&auml;chsten Bedingung weiter. Falls nicht, m&uuml;ssen wir dem Benutzer mitteilen, was nicht in Ordnung ist oder dies selbst beheben.<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>OptionentabelleVerknuepfen()<span style=\"color:blue;\"> As Boolean<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>bol<span style=\"color:blue;\"> As Boolean<\/span>\r\n     <span style=\"color:blue;\">If <\/span>IstBackendVorhanden<span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">If <\/span>IstOptionentabelleVorhanden<span style=\"color:blue;\"> Then<\/span>\r\n             <span style=\"color:blue;\">If <\/span>IstVerknuepfungVorhanden<span style=\"color:blue;\"> Then<\/span>\r\n                 <span style=\"color:blue;\">If <\/span>IstVerknuepfungKorrekt<span style=\"color:blue;\"> Then<\/span>\r\n                     bol = <span style=\"color:blue;\">True<\/span>\r\n                 <span style=\"color:blue;\">Else<\/span>\r\n                     <span style=\"color:blue;\">MsgBox<\/span> \"Die Verkn&uuml;pfung ist nicht korrekt.\"\r\n                 <span style=\"color:blue;\">End If<\/span>\r\n             <span style=\"color:blue;\">Else<\/span>\r\n                 <span style=\"color:blue;\">MsgBox<\/span> \"Die Verkn&uuml;pfungstabelle fehlt.\"\r\n             <span style=\"color:blue;\">End If<\/span>\r\n         <span style=\"color:blue;\">Else<\/span>\r\n             <span style=\"color:blue;\">MsgBox<\/span> \"Die Tabelle '\" & cStrOptionentabelle & \"' konnte nicht in der folgenden Datenbank gefunden \" _\r\n                 & \"werden:\" & <span style=\"color:blue;\">vbCrLf<\/span> & <span style=\"color:blue;\">vbCrLf<\/span> & CurrentProject.Path & \"\" & cStrOptionenbackend\r\n         <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">Else<\/span>\r\n         <span style=\"color:blue;\">MsgBox<\/span> \"Die Datenbank '\" & cStrOptionenbackend & \"' mit der Optionentabelle konnte nicht gefunden werden.\"\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     OptionentabelleVerknuepfen = bol\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 2: Pr&uuml;fen aller Bedingungen in einer Funktion<\/span><\/b><\/p>\n<p>Die n&auml;chste Bedingung pr&uuml;fen wir mit der Funktion <b>IstOptionentabelleVorhanden<\/b>. Auch hier geben wir eine Meldung aus, wenn die Bedingung nicht erf&uuml;llt wurde.<\/p>\n<p>Liefert die Funktion jedoch den Wert <b>True<\/b>, dann gehen wir mit der Pr&uuml;fung der n&auml;chsten Bedingung weiter &#8211; also <b>IstVerknuepfungVorhanden <\/b>&#8211; und dann mit <b>IstVerknuep-fungKorrekt<\/b>. In beiden F&auml;llen wird f&uuml;r den Wert <b>False <\/b>eine entsprechende Meldung ausgegeben.<\/p>\n<p><b>Optionentabelle verkn&uuml;pfen mit Korrekturm&ouml;glichkeit<\/b><\/p>\n<p>Nun wollen wir dem Benutzer noch die M&ouml;glichkeit geben, selbst die nicht erf&uuml;llten Bedingungen zu erf&uuml;llen und die Bedingungen dann erneut zu pr&uuml;fen. Dazu m&uuml;ssen wir die ganzen <b>If&#8230;Then<\/b>-Bedingungen in eine Schleife einfassen, die pr&uuml;ft, ob <b>bol <\/b>den Wert <b>True <\/b>liefert, was der Fall ist, wenn alle Bedingungen erf&uuml;llt sind. <\/p>\n<p>Wir m&uuml;ssen aber auch in Erw&auml;gung ziehen, dass der Benutzer oder die Anwendung selbst die Bedingungen nicht erf&uuml;llen k&ouml;nnen &#8211; beispielsweise wenn der Benutzer die Backend-Datenbank per Dateiauswahl-Dialog ausw&auml;hlen soll, weil diese gegebenenfalls an einem anderen Ort liegt, an dem sich auch die Frontend-Datenbank vorher befunden hat, aber diese Datenbank nicht findet. Dann soll der Benutzer die M&ouml;glichkeit erhalten, die Schleife abzubrechen.<\/p>\n<p>Dazu haben wir die Funktion <b>OptionentabelleVerknuep-fen <\/b>wie in Listing 3 ordentlich aufgebohrt. Als Erstes finden wir hier die schon angesproche <b>Do While<\/b>-Schleife, die erst abgebrochen wird, wenn die Variable <b>bol <\/b>den Wert <b>True <\/b>aufweist. Diese Variable wird erst in der inneren der vier verschachtelten <b>If&#8230;Then<\/b>-Bedingungen auf <b>True <\/b>eingestellt. Dadurch ist die Funktion noch nicht beendet, nur weil eine der vier Bedingungen nicht erf&uuml;llt ist. In diesem Fall erfolgt die f&uuml;r das Nichterf&uuml;llen der Bedingung vorgesehe Aktion, die wir uns gleich anschauen, und nach einer eventuellen Korrektur dieser Bedingung werden die Bedingungen nochmals gepr&uuml;ft.<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>OptionentabelleVerknuepfen()<span style=\"color:blue;\"> As Boolean<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>bol<span style=\"color:blue;\"> As Boolean<\/span>\r\n     <span style=\"color:blue;\">Do While<\/span> bol = <span style=\"color:blue;\">False<\/span>\r\n         <span style=\"color:blue;\">If <\/span>IstBackendVorhanden<span style=\"color:blue;\"> Then<\/span>\r\n             <span style=\"color:blue;\">If <\/span>IstOptionentabelleVorhanden<span style=\"color:blue;\"> Then<\/span>\r\n                 <span style=\"color:blue;\">If <\/span>IstVerknuepfungVorhanden<span style=\"color:blue;\"> Then<\/span>\r\n                     <span style=\"color:blue;\">If <\/span>IstVerknuepfungKorrekt<span style=\"color:blue;\"> Then<\/span>\r\n                         bol = <span style=\"color:blue;\">True<\/span>\r\n                     <span style=\"color:blue;\">Else<\/span>\r\n                         VerknuepfungKorrigieren\r\n                     <span style=\"color:blue;\">End If<\/span>\r\n                 <span style=\"color:blue;\">Else<\/span>\r\n                     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> VerknuepfungstabelleAnlegen<span style=\"color:blue;\"> Then<\/span>\r\n                         <span style=\"color:blue;\">MsgBox<\/span> \"Die Verkn&uuml;pfungstabelle '\" & cStrOptionentabelle & \"' konnte nicht angelegt \" _\r\n                             & \"werden. Wenden Sie sich an den Entwickler.\"\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;\">Else<\/span>\r\n                 <span style=\"color:blue;\">MsgBox<\/span> \"Die Tabelle '\" & cStrOptionentabelle & \"' konnte nicht in der folgenden Datenbank \" _\r\n                     & \"gefunden werden:\" & <span style=\"color:blue;\">vbCrLf<\/span> & <span style=\"color:blue;\">vbCrLf<\/span> & CurrentProject.Path & \"\" & cStrOptionenbackend & <span style=\"color:blue;\">vbCrLf<\/span> _\r\n                     & <span style=\"color:blue;\">vbCrLf<\/span> & \"Setzen Sie sich mit dem Hersteller in Verbindung, um die Optionendatenbank \" _\r\n                     & \"wiederherzustellen.\"\r\n                 <span style=\"color:blue;\">Exit Function<\/span>\r\n             <span style=\"color:blue;\">End If<\/span>\r\n         <span style=\"color:blue;\">Else<\/span>\r\n             <span style=\"color:blue;\">MsgBox<\/span> \"Die Datenbank '\" & cStrOptionenbackend & \"' mit der Optionentabelle konnte nicht gefunden \" _\r\n                 & \"werden. W&auml;hlen Sie diese nun selbst aus.\"\r\n             <span style=\"color:blue;\">If <\/span>BackendAuswaehlen = <span style=\"color:blue;\">False<\/span><span style=\"color:blue;\"> Then<\/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;\">Loop<\/span>\r\n     OptionentabelleVerknuepfen = bol\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 3: Pr&uuml;fen aller Bedingungen in einer Funktion, erweiterte Fassung<\/span><\/b><\/p>\n<p>Wenn die erste Bedingung, das Vorhandensein der Backend-Datenbank, nicht erf&uuml;llt ist, soll der Benutzer die Gelegenheit erhalten, diese gegebenenfalls beim Verschieben liegengebliebene oder anderweitig entfernte Datenbankdatei aufzufinden und zu erlauben, diese in das Verzeichnis der Frontend-Datenbank zu kopieren.<\/p>\n<p>Dazu haben wir im <b>Else<\/b>-Teil dieser Bedingung den Aufruf einer Funktion namens <b>BackendAuswaehlen <\/b>eingef&uuml;gt, die wie in Listing 4 aussieht. Hier rufen wir mit der Funktion <b>OpenFileName <\/b>einen Dateiauswahl-Dialog auf, mit dem der Benutzer ausgehend vom aktuellen Verzeichnis die Optionen-Backend-Datenbank ausw&auml;hlen kann. Wurde eine Datei ausgew&auml;hlt, fragt die Prozedur den Benutzer, ob die gew&auml;hlte Datei in das Verzeichnis der Frontend-Datenbank kopiert werden darf. Dies wird bei Best&auml;tigung mit der <b>Ja<\/b>-Schaltfl&auml;che durch die <b>FileCopy<\/b>-Methode erledigt. Danach pr&uuml;ft die Funktion erneut durch einen Aufruf der weiter oben beschriebenen Funktion <b>IstBackendVorhanden<\/b>, ob das Backend nun vorhanden ist und gibt in diesem Fall den Wert <b>True <\/b>zur&uuml;ck.<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>BackendAuswaehlen()<span style=\"color:blue;\"> As Boolean<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strPfad<span style=\"color:blue;\"> As String<\/span>\r\n     strPfad = OpenFileName(CurrentProject.Path, \"Optionen-Backend ausw&auml;hlen:\", \"Access-Datenbank (*.accdb)\")\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> <span style=\"color:blue;\">Len<\/span>(strPfad) = 0<span style=\"color:blue;\"> Then<\/span>\r\n         If <span style=\"color:blue;\">MsgBox<\/span>(\"Die Backenddatenbank wird nun in das Verzeichnis der aktuellen Datenbank kopiert. Fortsetzen\", _\r\n                 vbYesNo) = vbYes Then\r\n             FileCopy strPfad, CurrentProject.Path & \"\" & cStrOptionenbackend\r\n             <span style=\"color:blue;\">If <\/span>IstBackendVorhanden<span style=\"color:blue;\"> Then<\/span>\r\n                 BackendAuswaehlen = <span style=\"color:blue;\">True<\/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;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 4: Ausw&auml;hlen des Backends und Kopieren in das Datenbankverzeichnis<\/span><\/b><\/p>\n<p>Ist dies der Fall, steigt die aufrufende Funktion <b>OptionentabelleVerknuepfen <\/b>erneut in die <b>Do While<\/b>-Schleife ein, wobei diesmal die Backend-Datenbank gefunden werden sollte. Damit folgt die zweite Bedingung, die &#8211; wenn die Optionentabelle nicht im Backend gefunden wird &#8211; zum Abbruch der Funktion f&uuml;hrt mit der Meldung, dass der Benutzer sich an den Entwickler der Datenbank wenden soll. Das k&ouml;nnte man auch noch anders l&ouml;sen, indem man die Tabelle einfach neu in der Datenbank anlegt. Allerdings wissen wir an dieser Stelle ja noch nicht einmal, wie die Optionentabelle aussieht und lassen dies daher aus.<\/p>\n<p>Die dritte Bedingung f&uuml;hrt dann, wenn sie nicht erf&uuml;llt ist, wieder zum Aufruf einer weiteren Funktion, n&auml;mlich <b>VerknuepfungstabelleAnlegen<\/b>. Diese finden Sie in Listing 5. Diese Funktion erstellt ein neues <b>TableDef<\/b>-Objekt in der Frontend-Datenbank. Sie stellt die Eigenschaft <b>SourceTableName <\/b>auf den Wert aus <b>cStrOptionenTabelle <\/b>ein. Au&szlig;erdem legt sie den Wert der Eigenschaft <b>Connect <\/b>auf die Zeichenkette <b>;DATABASE=<\/b>, das Frontend-Verzeichnis und den Namen der Datenbank aus <b>cStrOptionenbackend <\/b>fest. Die Verkn&uuml;pfung ist nun zwar erstellt, aber noch nicht an die Liste der Tabellendefinitionen angeh&auml;ngt. Das erledigt die Prozedur, indem sie die <b>Append<\/b>-Methode der <b>TableDefs<\/b>-Auflistung aufruft und die Variable <b>tdf <\/b>als Parameter &uuml;bergibt. Danach aktualisiert sie die Auflistung mit der <b>Refresh<\/b>-Methode. Auch der Navigationsbereich wird aktualisiert, damit die neue Verkn&uuml;pfung dort angezeigt wird. Dazu rufen wir die <b>RefreshDatabaseWindow<\/b>-Methode des <b>Application<\/b>-Objekts auf. Ob der Vorgang gelungen ist, pr&uuml;fen wir danach durch einen Aufruf der Funktion <b>IstVerknuepfungVorhanden<\/b>. Liefert diese den Wert <b>True<\/b>, stellen wir als R&uuml;ckgabewert der Funktion <b>VerknuepfungstabelleAnlegen <\/b>den Wert <b>True <\/b>ein.<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>VerknuepfungstabelleAnlegen()<span style=\"color:blue;\"> As Boolean<\/span>\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>tdf<span style=\"color:blue;\"> As <\/span>DAO.TableDef\r\n     <span style=\"color:blue;\">Set<\/span> db = CurrentDb\r\n     <span style=\"color:blue;\">Set<\/span> tdf = db.CreateTableDef(cStrOptionentabelle)\r\n     <span style=\"color:blue;\">With<\/span> tdf\r\n         .SourceTableName = cStrOptionentabelle\r\n         tdf.Connect = \";database=\" & CurrentProject.Path & \"\" & cStrOptionenbackend\r\n         db.TableDefs.Append tdf\r\n         db.TableDefs.Refresh\r\n         Application.RefreshDatabaseWindow\r\n     End <span style=\"color:blue;\">With<\/span>\r\n     <span style=\"color:blue;\">If <\/span>IstVerknuepfungVorhanden<span style=\"color:blue;\"> Then<\/span>\r\n         VerknuepfungstabelleAnlegen = <span style=\"color:blue;\">True<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 5: Anlegen der Verkn&uuml;pfungstabelle<\/span><\/b><\/p>\n<p>Schlie&szlig;lich folgt noch in der letzten, inneren <b>If&#8230;Then<\/b>-Bedingung die Pr&uuml;fung, ob die Verkn&uuml;pfung korrekt ist, also ob die richtige Datenbankdatei und die richtige Tabelle verkn&uuml;pft sind. Der Aufruf der dazu verwendeten Funktion <b>IstVerknuepfungKorrekt <\/b>ist theoretisch nicht mehr n&ouml;tig, wenn beim vorherigen Durchlauf der <b>Do While<\/b>-Schleife die Prozedur <b>VerknuepfungstabelleAnlegen <\/b>aufgerufen wurde.<\/p>\n<p>Anderenfalls kann es aber geschehen, dass die Verkn&uuml;pfung auf eine falsche Datenbank oder Tabelle verweist. Da die anderen Schritte zu diesem Zeitpunkt schon durchlaufen wurden und die Bedingungen erf&uuml;llt sind, dass die Optionen-Backend-Datenbank vorhanden ist und dass diese auch die Tabelle aus <b>cStrOptionentabelle <\/b>enth&auml;lt, k&ouml;nnen wir, wenn <b>IstVerknuepfungKorrekt <\/b>den Wert <b>False<\/b> liefert, die Verkn&uuml;pfung l&ouml;schen und neu erstellen. Das erledigen wir in der folgenden Prozedur aus Listing 6. Die Prozedur ist &auml;hnlich wie die zuvor beschriebene Funktion <b>VerknuepfungstabelleAnlegen <\/b>aufgebaut.<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>VerknuepfungKorrigieren()\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>tdf<span style=\"color:blue;\"> As <\/span>DAO.TableDef\r\n     <span style=\"color:blue;\">Set<\/span> tdf = db.TableDefs(cStrOptionentabelle)\r\n     <span style=\"color:blue;\">With<\/span> tdf\r\n         .SourceTableName = cStrOptionentabelle\r\n         tdf.Connect = \";database=\" & CurrentProject.Path & \"\" & cStrOptionenbackend\r\n         db.TableDefs.Append tdf\r\n         db.TableDefs.Refresh\r\n         Application.RefreshDatabaseWindow\r\n     End <span style=\"color:blue;\">With<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 6: Aktualisieren der Verkn&uuml;pfungstabelle<\/span><\/b><\/p>\n<p>Allerdings erstellt sie zu Beginn nicht das <b>TableDefs<\/b>-Objekt neu, sondern verwendet das vorhandene <b>TableDefs<\/b>-Objekt mit dem Namen aus <b>cStrOptionentabelle <\/b>und referenziert diese mit der Variablen <b>tdf<\/b>. Dann f&uuml;hrt sie die gleichen Schritte wie die obige Funktion durch, also das Zuweisen der Tabelle der Quelldatenbank, die Verbindung zur Quelldatenbank, das Anh&auml;ngen des <b>TableDefs<\/b>-Objekts an die Auflistung <b>TableDefs <\/b>und das Aktualisieren von <b>TableDefs<\/b>-Auflistung und Navigationsbereich.<\/p>\n<p><b>Funktionen im &Uuml;berblick<\/b><\/p>\n<p>Schauen wir uns nun an, wie diese Funktionen zusammenspielen. Dazu haben wir ein Flussdiagramm erstellt, das Sie in Bild 3 finden. Hier erkennen Sie unterhalb von Start die vier Bedingungen, die erf&uuml;llt sein m&uuml;ssen, damit wir schlie&szlig;lich mit dem Funktionswert <b>True <\/b>zum Ende der Funktion gelangen.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2020_01\/pic_1220_004.pdf\" alt=\"Ablauf der Prozeduren\" width=\"700\" height=\"668,6567\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 3: Ablauf der Prozeduren<\/span><\/b><\/p>\n<p>Wenn eine der Bedingungen nicht erf&uuml;llt ist, geht es entweder weiter mit dem Ausw&auml;hlen des Backends, dem Abbruch, falls die Optionentabelle nicht im Backend gefunden werden kann, dem Anlegen der Verkn&uuml;pfung oder dem Korrigieren der Verkn&uuml;pfung. Mit Ausnahme des Abbruchs gelangen wir &uuml;ber die <b>Do While<\/b>-Schleife immer wieder an den Startpunkt.<\/p>\n<p><b>Optionen lesen und schreiben<\/b><\/p>\n<p>Nun schauen wir uns noch die M&ouml;glichkeiten von VBA zum Lesen und Schreiben der Optionen an, und zwar f&uuml;r beide eingangs vorgestellten Tabellenarten &#8211; sowohl f&uuml;r die Tabelle mit je einer Option pro Feld als auch mit je einer Option pro Datensatz. Wir beginnen mit der Tabelle mit einer Option je Feld.<\/p>\n<p><b>Optionen in Tabelle mit einer Option je Feld schreiben<\/b><\/p>\n<p>Wenn wir die Tabelle <b>tblOptionen_Felder<\/b>, die wir weiter oben bereits beschrieben haben, zum Speichern von Optionen verwenden, k&ouml;nnen wir theoretisch die Optionen einfach mit einer <b>DLookup<\/b>-Anweisung lesen und mit einer <b>UPDATE<\/b>-Aktionsabfrage in die Tabelle schreiben.<\/p>\n<p>Es gibt jedoch einen Umstand, der zu Problemen f&uuml;hren kann: Die Tabelle hat nicht zwingend einen Datensatz mit dem vorgesehenen Satz von Optionen. Es kann sein, dass die Tabelle ohne Daten ausgeliefert wird oder dass der Datensatz mit den Optionen aus nicht vorhersehbaren Gr&uuml;nden gel&ouml;scht wird.<\/p>\n<p>Wir m&uuml;ssen also vor dem Lesen und Schreiben von Optionswerten zun&auml;chst pr&uuml;fen, ob &uuml;berhaupt genau ein Datensatz in der Tabelle <b>tblOptionen_Felder <\/b>enthalten ist. Die n&auml;chste Frage, die sich stellt, ist die folgende: Wie gehen wir mit der Tatsache um, dass die einzelnen Felder unterschiedliche Datentypen aufweisen k&ouml;nnen Und warum ist das &uuml;berhaupt eine Frage <\/p>\n<p>Es gibt zwei M&ouml;glichkeiten, den Wert eines Feldes zu &auml;ndern:<\/p>\n<ul>\n<li>Sie versetzen den Datensatz mit der <b>DAO<\/b>-Methode <b>Edit <\/b>in den Bearbeitungszustand, weisen dem Feld den gew&uuml;nschten Wert zu und speichern diesen dann mit der <b>Update<\/b>-Methode.<\/li>\n<li>Sie aktualisieren den Datensatz mit der <b>Execute<\/b>-Methode des <b>Database<\/b>-Objekts und f&uuml;hren damit eine <b>UPDATE<\/b>-Abfrage aus.<\/li>\n<\/ul>\n<p>Die zweite M&ouml;glichkeit erwartet f&uuml;r unterschiedliche Datentypen eine leicht unterschiedliche Schreibweise. Zahlenwerte k&ouml;nnen direkt angegeben werden (allerdings mit dem passenden Dezimaltrennzeichen), Zeichenketten f&uuml;r Textfelder hingegen m&uuml;ssen in Hochkommata oder Anf&uuml;hrungszeichen eingefasst werden. Wir m&uuml;ssten hier also pr&uuml;fen, um welchen Datentyp es sich jeweils handelt. Bei der Verwendung der DAO-Methoden ist das nicht n&ouml;tig. Daher nutzen wir diese im aktuellen Anwendungsfall.<\/p>\n<p>Die resultierende Funktion sieht damit wie in Listing 7 aus. Die Funktion <b>Option-Schreiben <\/b>erwartet den Namen der Option sowie den neuen Wert als Parameter. Sie &ouml;ffnet ein Recordset auf Basis der Tabelle aus <b>cStrOptionentabelle <\/b>und versucht zun&auml;chst, das Feld mit dem Namen aus dem Parameter <b>strOption <\/b>zu referenzieren. Wenn das nicht gelingt, ist das Feld offensichtlich nicht vorhanden und es erscheint vor dem Abbruch der Funktion eine entsprechende Meldung. Anderenfalls l&auml;uft die Prozedur weiter und pr&uuml;ft, ob bereits das Ende des Recordsets erreicht ist, was bedeuten w&uuml;rde, dass das Recordset keinen Datensatz enth&auml;lt. In diesem Fall f&uuml;gt sie mit der <b>AddNew<\/b>-Methode einen neuen Datensatz zum Recordset hinzu. Anderenfalls versetzt sie den ersten Datensatz mit der <b>Edit<\/b>-Methode in den Bearbeitungszustand. In beiden F&auml;llen weist die Prozedur dem Feld aus <b>strOption <\/b>den Wert aus <b>strWert <\/b>zu und speichert die &Auml;nderung mit der <b>Update<\/b>-Methode in der Tabelle. In diesem Fall liefert die Funktion den Wert <b>True <\/b>zur&uuml;ck.<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>OptionSchreiben(strOption<span style=\"color:blue;\"> As String<\/span>, varWert<span style=\"color:blue;\"> As Variant<\/span>)<span style=\"color:blue;\"> As Boolean<\/span>\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>strTabelle<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>fld<span style=\"color:blue;\"> As <\/span>DAO.Field\r\n     <span style=\"color:blue;\">Dim <\/span>rst<span style=\"color:blue;\"> As <\/span>DAO.Recordset\r\n     strTabelle = cStrOptionentabelle\r\n     <span style=\"color:blue;\">Set<\/span> db = CurrentDb\r\n     <span style=\"color:blue;\">Set<\/span> rst = db.OpenRecordset(\"SELECT * FROM \" & strTabelle, dbOpenDynaset)\r\n     On Error Resume <span style=\"color:blue;\">Next<\/span>\r\n     <span style=\"color:blue;\">Set<\/span> fld = rst.Fields(strOption)\r\n     <span style=\"color:blue;\">On Error GoTo<\/span> 0\r\n     <span style=\"color:blue;\">If <\/span>fld Is Nothing<span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">MsgBox<\/span> \"Das Feld '\" & strOption & \"' ist nicht in der Optionentabelle enthalten.\"\r\n         <span style=\"color:blue;\">Exit Function<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">If <\/span>rst.EOF<span style=\"color:blue;\"> Then<\/span>\r\n         rst.Add<span style=\"color:blue;\">New<\/span>\r\n     <span style=\"color:blue;\">Else<\/span>\r\n         rst.Edit\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     rst.Fields(strOption) = varWert\r\n     rst.Update\r\n     OptionSchreiben = <span style=\"color:blue;\">True<\/span>\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 7: Schreiben eines Optionswertes<\/span><\/b><\/p>\n<p><b>Optionen aus Tabelle mit einer Option je Feld lesen<\/b><\/p>\n<p>Die Funktion aus Listing 8 zeigt, wie die Werte aus der Tabelle mit einem Feld je Option gelesen werden. Sie enth&auml;lt zun&auml;chst den gleichen Ablauf wie die Funktion zum Schreiben einer Option. Sie erwartet den Namen der zu lesenden Option als Parameter und &ouml;ffnet ebenfalls ein Recordset auf Basis der Optionentabelle. Danach folgt die gleiche Pr&uuml;fung auf Vorhandensein des Feldes f&uuml;r die angefragte Option. Mit der folgenden Bedingung pr&uuml;ft die Funktion dann, ob ein Datensatz in der Tabelle enthalten ist. Falls nicht, erscheint eine entsprechende Meldung und die Funktion wird beendet. Anderenfalls stellt die Funktion ihren R&uuml;ckgabewert auf den Wert des angegebenen Feldes ein.<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>OptionLesen(strOption<span style=\"color:blue;\"> As String<\/span>)<span style=\"color:blue;\"> As Variant<\/span>\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>rst<span style=\"color:blue;\"> As <\/span>DAO.Recordset\r\n     <span style=\"color:blue;\">Dim <\/span>strTabelle<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>fld<span style=\"color:blue;\"> As <\/span>DAO.Field\r\n     <span style=\"color:blue;\">Set<\/span> db = CurrentDb\r\n     strTabelle = cStrOptionentabelle\r\n     <span style=\"color:blue;\">Set<\/span> rst = db.OpenRecordset(\"SELECT * FROM \" & strTabelle, dbOpenDynaset)\r\n     On Error Resume <span style=\"color:blue;\">Next<\/span>\r\n     <span style=\"color:blue;\">Set<\/span> fld = rst.Fields(strOption)\r\n     <span style=\"color:blue;\">On Error GoTo<\/span> 0\r\n     <span style=\"color:blue;\">If <\/span>fld Is Nothing<span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">MsgBox<\/span> \"Das Feld '\" & strOption & \"' ist nicht in der Optionentabelle enthalten.\"\r\n         <span style=\"color:blue;\">Exit Function<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">If <\/span>rst.EOF<span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">MsgBox<\/span> \"Die Optionentabelle enth&auml;lt keine Daten.\"\r\n         <span style=\"color:blue;\">Exit Function<\/span>\r\n     <span style=\"color:blue;\">Else<\/span>\r\n         OptionLesen = rst.Fields(strOption)\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 8: Lesen eines Optionswertes<\/span><\/b><\/p>\n<p><b>Wechsel zur Name-Wert-Optionentabelle<\/b><\/p>\n<p>Nun schauen wir uns noch die Funktionen an, mit denen Sie die Optionen in eine Tabelle schreiben, in der f&uuml;r jede Option ein eigener Datensatz vorgesehen ist. Falls diese Tabelle noch nicht mit der Frontend-Datenbank verkn&uuml;pft ist, &auml;ndern Sie zun&auml;chst die folgende Konstante:<\/p>\n<pre><span style=\"color:blue;\">Public <\/span>Const cStrOptionentabelle<span style=\"color:blue;\"> As String<\/span> =  \"tblOptionen_NameWert\"<\/pre>\n<p>Danach rufen Sie die Funktion <b>OptionentabelleVerknuepfen <\/b>erneut auf. Dies erstellt eine neue Verkn&uuml;pfung, diesmal mit der Tabelle <b>tblOptionen_NameWert<\/b>.<\/p>\n<p><b>Optionen in Tabelle mit einer Option je Datensatz schreiben<\/b><\/p>\n<p>Mit der Version der Funktion <b>OptionSchreiben <\/b>aus Listing 9 k&ouml;nnen Sie Optionswerte in die Tabelle <b>tblOptionen_NameWert <\/b>eintragen. Die Funktion erstellt ein Recordset auf Basis dieser Tabelle, das alle Datens&auml;tze enth&auml;lt, deren Feld <b>Optionsname <\/b>den Wert des Parameters <b>strOption <\/b>aufweist. Enth&auml;lt das Recordset noch keinen solchen Datensatz, f&uuml;gen wir diesen mit der <b>AddNew<\/b>-Methode hinzu und tragen auch gleich den Optionsnamen in das Feld <b>Optionsname <\/b>ein. Ist der Datensatz bereits vorhanden, aktivieren wir lediglich mit der <b>Edit<\/b>-Methode den Bearbeitungsmodus.<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>OptionSchreiben(strOption<span style=\"color:blue;\"> As String<\/span>, varWert<span style=\"color:blue;\"> As Variant<\/span>)<span style=\"color:blue;\"> As Boolean<\/span>\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>rst<span style=\"color:blue;\"> As <\/span>DAO.Recordset\r\n     <span style=\"color:blue;\">Dim <\/span>strTabelle<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Set<\/span> db = CurrentDb\r\n     strTabelle = cStrOptionentabelle\r\n     <span style=\"color:blue;\">Set<\/span> rst = db.OpenRecordset(\"SELECT * FROM \" & strTabelle _\r\n         & \" WHERE Optionsname = '\" & strOption & \"'\", dbOpenDynaset)\r\n     <span style=\"color:blue;\">If <\/span>rst.EOF<span style=\"color:blue;\"> Then<\/span>\r\n         rst.Add<span style=\"color:blue;\">New<\/span>\r\n         rst!Optionsname = strOption\r\n     <span style=\"color:blue;\">Else<\/span>\r\n         rst.Edit\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     rst!Optionswert = varWert\r\n     rst.Update\r\n     OptionSchreiben = <span style=\"color:blue;\">True<\/span>\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 9: Schreiben eines Optionswertes in einen Name\/Wert-Datensatz<\/span><\/b><\/p>\n<p>In beiden F&auml;llen tragen wir dann den Wert der Option in das Feld <b>Optionswert <\/b>ein und speichern die &Auml;nderung in die zugrunde liegende Tabelle.<\/p>\n<p><b>Optionen aus Tabelle mit einer Option pro Datensatz lesen<\/b><\/p>\n<p>Die Funktion <b>OptionLesen<\/b> f&uuml;r die Name\/Wert-Optionentabelle liest wiederum ein Recordset auf Basis der Tabelle aus <b>cStrOptionentabelle <\/b>ein, dessen Feld <b>Optionsname <\/b>dem Wert des Parameters <b>strOption <\/b>entsprechen soll (siehe Listing 10).<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>OptionLesen(strOption<span style=\"color:blue;\"> As String<\/span>)<span style=\"color:blue;\"> As Variant<\/span>\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>rst<span style=\"color:blue;\"> As <\/span>DAO.Recordset\r\n     <span style=\"color:blue;\">Dim <\/span>strTabelle<span style=\"color:blue;\"> As String<\/span>\r\n     strTabelle = cStrOptionentabelle\r\n     <span style=\"color:blue;\">Set<\/span> db = CurrentDb\r\n     <span style=\"color:blue;\">Set<\/span> rst = db.OpenRecordset(\"SELECT * FROM \" & strTabelle _\r\n         & \" WHERE Optionsname = '\" & strOption & \"'\", dbOpenDynaset)\r\n     <span style=\"color:blue;\">If <\/span>rst.EOF<span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">MsgBox<\/span> \"Die Option '\" & strOption & \"' ist nicht gesetzt.\"\r\n     <span style=\"color:blue;\">Else<\/span>\r\n         OptionLesen = rst!Optionswert\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 10: Lesen eines Optionswertes aus einer Name\/Wert-Tabelle<\/span><\/b><\/p>\n<p>Ist das Recordset leer, wird eine Meldung ausgegeben, dass die Option nicht gesetzt ist. Anderenfalls liefert die Funktion den Wert des Feldes <b>Optionswert <\/b>f&uuml;r den gefundenen Datensatz zur&uuml;ck.<\/p>\n<p><b>Zusammenfassung und Ausblick<\/b><\/p>\n<p>Im ersten Teil dieser Beitragsreihe haben wir gezeigt, wie Sie Optionen in eine eigene Backend-Optionendatenbank auslagern und den Zugriff auf die dort gespeicherten Informationen sicherstellen. Im zweiten Teil schauen wir uns in der n&auml;chsten Ausgabe an, wie eine L&ouml;sung mit Optionentabelle im Daten-Backend einer Mehrbenutzeranwendung aussehen kann.<\/p>\n<h3>Downloads zu diesem Beitrag<\/h3>\n<p>Enthaltene Beispieldateien:<\/p>\n<p>OptionenImBackendSpeichern.accdb<\/p>\n<p>Backend_Optionen.accdb<\/p>\n<p><a href=\"..\/fileadmin\/beispiele\/A4396853-B4FA-4410-A451-56B248904EA2\/aiu_1220.zip\">Download<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Wenn mehrere Benutzer &uuml;ber Frontend-Anwendungen an verschiedenen Arbeitspl&auml;tzen auf die Daten einer Backend-Datenbank zugreifen, ist das kein Problem. In vielen Anwendungen ist es dabei sinnvoll, die M&ouml;glichkeit zum Speichern von Optionen je Benutzer vorzusehen. Oft legt man dabei eine Tabelle namens &#8222;tblOptionen&#8220; im Frontend an. Das ist aber nur sinnvoll, wenn auch immer der gleiche Benutzer am gleichen Frontend arbeitet &#8211; anderenfalls w&uuml;rde er ja die Optionen eines anderen Benutzers vorgesetzt bekommen. Oder Sie f&uuml;hren ein Update des Frontends durch &#8211; auch dann w&auml;ren die Optionen des Benutzers nicht mehr vorhanden. Welche Alternativen dazu gibt es Sie k&ouml;nnten zum Beispiel die Optionen in einer Tabelle im Backend speichern und diese beim Anmelden des Benutzers auslesen und in eine lokale Optionentabelle &uuml;bertragen. Oder Sie f&uuml;gen dem Frontend ein  lokales Backend hinzu, das nur die Daten enth&auml;lt, die beim Update des Frontends nicht &uuml;berschrieben werden sollen. Wie das gelingt, zeigen wir im vorliegenden Artikel.<\/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":[66012020,662020,44000021],"tags":[],"class_list":["post-55001220","post","type-post","status-publish","format-standard","hentry","category-66012020","category-662020","category-Tabellen_und_Datenmodellierung"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v20.9 (Yoast SEO v27.4) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Optionen und andere Daten updatesicher speichern - 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\/Optionen_und_andere_Daten_updatesicher_speichern\/\" \/>\n<meta property=\"og:locale\" content=\"de_DE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Optionen und andere Daten updatesicher speichern\" \/>\n<meta property=\"og:description\" content=\"Wenn mehrere Benutzer &uuml;ber Frontend-Anwendungen an verschiedenen Arbeitspl&auml;tzen auf die Daten einer Backend-Datenbank zugreifen, ist das kein Problem. In vielen Anwendungen ist es dabei sinnvoll, die M&ouml;glichkeit zum Speichern von Optionen je Benutzer vorzusehen. Oft legt man dabei eine Tabelle namens &quot;tblOptionen&quot; im Frontend an. Das ist aber nur sinnvoll, wenn auch immer der gleiche Benutzer am gleichen Frontend arbeitet - anderenfalls w&uuml;rde er ja die Optionen eines anderen Benutzers vorgesetzt bekommen. Oder Sie f&uuml;hren ein Update des Frontends durch - auch dann w&auml;ren die Optionen des Benutzers nicht mehr vorhanden. Welche Alternativen dazu gibt es Sie k&ouml;nnten zum Beispiel die Optionen in einer Tabelle im Backend speichern und diese beim Anmelden des Benutzers auslesen und in eine lokale Optionentabelle &uuml;bertragen. Oder Sie f&uuml;gen dem Frontend ein lokales Backend hinzu, das nur die Daten enth&auml;lt, die beim Update des Frontends nicht &uuml;berschrieben werden sollen. Wie das gelingt, zeigen wir im vorliegenden Artikel.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/access-im-unternehmen.de\/Optionen_und_andere_Daten_updatesicher_speichern\/\" \/>\n<meta property=\"og:site_name\" content=\"Access im Unternehmen\" \/>\n<meta property=\"article:published_time\" content=\"2020-07-10T09:39:29+00:00\" \/>\n<meta property=\"og:image\" content=\"http:\/\/vg06.met.vgwort.de\/na\/c57e4e609dd7412b908182db6c4e6fde\" \/>\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\\\/Optionen_und_andere_Daten_updatesicher_speichern\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Optionen_und_andere_Daten_updatesicher_speichern\\\/\"},\"author\":{\"name\":\"Andr\u00e9 Minhorst\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/person\\\/13395c4bcd7d7963efe33be9c584d93f\"},\"headline\":\"Optionen und andere Daten updatesicher speichern\",\"datePublished\":\"2020-07-10T09:39:29+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Optionen_und_andere_Daten_updatesicher_speichern\\\/\"},\"wordCount\":4295,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Optionen_und_andere_Daten_updatesicher_speichern\\\/#primaryimage\"},\"thumbnailUrl\":\"http:\\\/\\\/vg06.met.vgwort.de\\\/na\\\/c57e4e609dd7412b908182db6c4e6fde\",\"articleSection\":[\"1\\\/2020\",\"2020\",\"Tabellen und Datenmodellierung\"],\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/access-im-unternehmen.de\\\/Optionen_und_andere_Daten_updatesicher_speichern\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Optionen_und_andere_Daten_updatesicher_speichern\\\/\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Optionen_und_andere_Daten_updatesicher_speichern\\\/\",\"name\":\"Optionen und andere Daten updatesicher speichern - Access im Unternehmen\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Optionen_und_andere_Daten_updatesicher_speichern\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Optionen_und_andere_Daten_updatesicher_speichern\\\/#primaryimage\"},\"thumbnailUrl\":\"http:\\\/\\\/vg06.met.vgwort.de\\\/na\\\/c57e4e609dd7412b908182db6c4e6fde\",\"datePublished\":\"2020-07-10T09:39:29+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Optionen_und_andere_Daten_updatesicher_speichern\\\/#breadcrumb\"},\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/access-im-unternehmen.de\\\/Optionen_und_andere_Daten_updatesicher_speichern\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Optionen_und_andere_Daten_updatesicher_speichern\\\/#primaryimage\",\"url\":\"http:\\\/\\\/vg06.met.vgwort.de\\\/na\\\/c57e4e609dd7412b908182db6c4e6fde\",\"contentUrl\":\"http:\\\/\\\/vg06.met.vgwort.de\\\/na\\\/c57e4e609dd7412b908182db6c4e6fde\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Optionen_und_andere_Daten_updatesicher_speichern\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Optionen und andere Daten updatesicher speichern\"}]},{\"@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":"Optionen und andere Daten updatesicher speichern - 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\/Optionen_und_andere_Daten_updatesicher_speichern\/","og_locale":"de_DE","og_type":"article","og_title":"Optionen und andere Daten updatesicher speichern","og_description":"Wenn mehrere Benutzer &uuml;ber Frontend-Anwendungen an verschiedenen Arbeitspl&auml;tzen auf die Daten einer Backend-Datenbank zugreifen, ist das kein Problem. In vielen Anwendungen ist es dabei sinnvoll, die M&ouml;glichkeit zum Speichern von Optionen je Benutzer vorzusehen. Oft legt man dabei eine Tabelle namens \"tblOptionen\" im Frontend an. Das ist aber nur sinnvoll, wenn auch immer der gleiche Benutzer am gleichen Frontend arbeitet - anderenfalls w&uuml;rde er ja die Optionen eines anderen Benutzers vorgesetzt bekommen. Oder Sie f&uuml;hren ein Update des Frontends durch - auch dann w&auml;ren die Optionen des Benutzers nicht mehr vorhanden. Welche Alternativen dazu gibt es Sie k&ouml;nnten zum Beispiel die Optionen in einer Tabelle im Backend speichern und diese beim Anmelden des Benutzers auslesen und in eine lokale Optionentabelle &uuml;bertragen. Oder Sie f&uuml;gen dem Frontend ein lokales Backend hinzu, das nur die Daten enth&auml;lt, die beim Update des Frontends nicht &uuml;berschrieben werden sollen. Wie das gelingt, zeigen wir im vorliegenden Artikel.","og_url":"https:\/\/access-im-unternehmen.de\/Optionen_und_andere_Daten_updatesicher_speichern\/","og_site_name":"Access im Unternehmen","article_published_time":"2020-07-10T09:39:29+00:00","og_image":[{"url":"http:\/\/vg06.met.vgwort.de\/na\/c57e4e609dd7412b908182db6c4e6fde","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\/Optionen_und_andere_Daten_updatesicher_speichern\/#article","isPartOf":{"@id":"https:\/\/access-im-unternehmen.de\/Optionen_und_andere_Daten_updatesicher_speichern\/"},"author":{"name":"Andr\u00e9 Minhorst","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/person\/13395c4bcd7d7963efe33be9c584d93f"},"headline":"Optionen und andere Daten updatesicher speichern","datePublished":"2020-07-10T09:39:29+00:00","mainEntityOfPage":{"@id":"https:\/\/access-im-unternehmen.de\/Optionen_und_andere_Daten_updatesicher_speichern\/"},"wordCount":4295,"commentCount":0,"publisher":{"@id":"https:\/\/access-im-unternehmen.de\/#organization"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/Optionen_und_andere_Daten_updatesicher_speichern\/#primaryimage"},"thumbnailUrl":"http:\/\/vg06.met.vgwort.de\/na\/c57e4e609dd7412b908182db6c4e6fde","articleSection":["1\/2020","2020","Tabellen und Datenmodellierung"],"inLanguage":"de","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/access-im-unternehmen.de\/Optionen_und_andere_Daten_updatesicher_speichern\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/access-im-unternehmen.de\/Optionen_und_andere_Daten_updatesicher_speichern\/","url":"https:\/\/access-im-unternehmen.de\/Optionen_und_andere_Daten_updatesicher_speichern\/","name":"Optionen und andere Daten updatesicher speichern - Access im Unternehmen","isPartOf":{"@id":"https:\/\/access-im-unternehmen.de\/#website"},"primaryImageOfPage":{"@id":"https:\/\/access-im-unternehmen.de\/Optionen_und_andere_Daten_updatesicher_speichern\/#primaryimage"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/Optionen_und_andere_Daten_updatesicher_speichern\/#primaryimage"},"thumbnailUrl":"http:\/\/vg06.met.vgwort.de\/na\/c57e4e609dd7412b908182db6c4e6fde","datePublished":"2020-07-10T09:39:29+00:00","breadcrumb":{"@id":"https:\/\/access-im-unternehmen.de\/Optionen_und_andere_Daten_updatesicher_speichern\/#breadcrumb"},"inLanguage":"de","potentialAction":[{"@type":"ReadAction","target":["https:\/\/access-im-unternehmen.de\/Optionen_und_andere_Daten_updatesicher_speichern\/"]}]},{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/access-im-unternehmen.de\/Optionen_und_andere_Daten_updatesicher_speichern\/#primaryimage","url":"http:\/\/vg06.met.vgwort.de\/na\/c57e4e609dd7412b908182db6c4e6fde","contentUrl":"http:\/\/vg06.met.vgwort.de\/na\/c57e4e609dd7412b908182db6c4e6fde"},{"@type":"BreadcrumbList","@id":"https:\/\/access-im-unternehmen.de\/Optionen_und_andere_Daten_updatesicher_speichern\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/access-im-unternehmen.de\/"},{"@type":"ListItem","position":2,"name":"Optionen und andere Daten updatesicher speichern"}]},{"@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\/55001220","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=55001220"}],"version-history":[{"count":0,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts\/55001220\/revisions"}],"wp:attachment":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/media?parent=55001220"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/categories?post=55001220"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/tags?post=55001220"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}