Lies diesen Artikel und viele weitere mit einem kostenlosen, einwöchigen Testzugang.
André Minhorst, Duisburg
Verwalten von Rezepten – das hört sich gar nicht nach einer Musterlösung für Unternehmen an. Oder sind nur Hotelköche angesprochen Nein. Neben dem Anspruch, ein Muster für eine Vielzahl von Anwendungen zu bieten, soll die vorliegende Musterlösung auch von einer Vielzahl von Anwendern auf ihre eigenen Bedürfnisse zugeschnitten werden können.
Schließlich gibt es zu vielen Tätigkeiten „Rezepte“ bzw. Verfahrensvorschriften, deren Durchführung auch noch die Verwendung bestimmter Zutaten – z. B. bestimmter Formulare – erfordert.
Neben der Verwaltung von Rezepten, Zutaten usw. werden Sie hier mit der Programmierung einer Schnittstelle konfrontiert. Diese dient dem Einlesen von fertigen Rezepten, von denen es im Internet Tausende gibt.
Wenn Sie sich z. B. einmal unter dem Stichwort Meal-Master die in Google registrierten deutschsprachigen Seiten ausgeben lassen, finden Sie zurzeit etwa 1.200 Einträge. Von vielen Seiten können Sie Dateien herunterladen, die teilweise hunderte von Rezepten enthalten.
Meal-Master ist ein amerikanisches Programm zur Verwaltung von Rezepten, das ein international anerkanntes Format für den Austausch von Rezepten enthält – die meisten verfügbaren Rezeptverwaltungen besitzen eine Funktion für den Import dieses Formats.
In diesem Zusammenhang lernen Sie auch, wie Sie mit einer Schnittstelle Daten von anderen Anwendungen in Ihre Datenbank importieren können. Der hier vorgestellte Vorgang lässt sich allerdings nicht mit denjenigen Assistenten vergleichen, die beispielsweise den Import von Daten aus Excel- oder CSV-Dateien erleichtern. Vielmehr zeigt dieser Beitrag, wie Daten in eine komplexe Datenstruktur eingearbeitet werden können.
Die Rezeptverwaltung soll neben ihrer eigentlichen Aufgabe, der Verwaltung von Rezepten, auch den Import und Export im Meal-Master-Format erlauben. Daher berücksichtigt das Datenmodell auch dessen weltweit gültiges Format, das in den folgenden Abschnitten kurz vorgestellt werden soll.
Das Meal-Master-Format
Meal-Master verwendet herkömmliche Textdateien. Es gibt eine genaue Spezifikation zur Festlegung der einzelnen Abschnitte eines Rezeptes. Ein Rezept besteht demnach aus den folgenden Angaben:
Aus diesen Informationen können Sie das Datenmodell zur Abbildung der Rezepte in einem relationalen Datenbanksystem – wie es Access ist – direkt ableiten.
Bild 1: Datenmodell der Rezeptverwaltung
Das Rezept als Hauptobjekt des Datenmodells benötigt eine eigene Tabelle zur Speicherung der rezeptspezifischen Daten. In diese Tabelle gehören der Rezeptname, die Anzahl der Portionen und die Anleitung – Informationen, die für jedes Rezept genau einmal auftauchen.
Anders verhält es sich mit den Kategorien und Zutaten: Jedes Rezept kann einer oder mehreren Kategorien zugeordnet werden und für jedes Rezept benötigen Sie in der Regel mehrere Zutaten.
Das gilt in beiden Fällen sicher auch umgekehrt: Sie ordnen jeder Kategorie ein oder mehrere Rezepte zu und auch jede Zutat taucht in einem oder in mehreren Rezepten auf.
Sie benötigen also zwei m:n-Beziehungen – sowohl zwischen Rezepten und Kategorien als auch zwischen Rezepten und Zutaten.
Die erste Beziehung realisieren Sie mit einer einfachen Verknüpfungstabelle. Die zweite zwischen Rezepten und Zutaten ist etwas komplizierter. Hier müssen Sie zusätzlich noch Informationen über Einheit und Anzahl der Zutaten hinzufügen.
Da diese Informationen sich unter Umständen bei jeder Kombination aus Rezepten und Zutaten unterscheiden, können Sie diese nur in der Verknüpfungstabelle zwischen den Tabellen der Rezepte und der Zutaten unterbringen.
Die Tabelle tblRezepte
Der Rezeptname, die Anleitung und die Anzahl der Portionen für die angegebenen Zutatenmengen speichern Sie in einer Tabelle namens tblRezepte. Da die Anleitung vermutlich oft länger als 255 Zeichen ist, verwenden Sie für diese Information ein Memo-Feld.
Die Tabelle tblZutaten
Alle in der Datenbank verwendeten Zutaten speichern Sie in der Tabelle tblZutaten. Neben der Bezeichnung der Zutat enthält die Tabelle ein Bemerkungsfeld.
Die Tabelle tblKategorien
Die Tabelle tblKategorien dient dem Speichern der Kategorien. Auch hier ist ein Bemerkungsfeld vorgesehen.
Die Tabelle tblEinheiten
Da es im Meal-Master-Format fest vorgegebene Einheiten gibt, die immer wieder auftauchen, sollen sie in einer separaten Tabelle gespeichert werden. Da die Bezeichnungen sich der Herkunft des Formats entsprechend auf amerikanische Einheiten beziehen, soll die Tabelle neben der englischen Bezeichnung auch noch eine deutsche Bezeichnung für die Ausgabe enthalten.
Die TabelletblRezepteZutaten
Diese Tabelle speichert alle Zuordnungen zwischen Rezepten und Zutaten. Zusätzlich soll die Tabelle zu jeder Zuordnung die Einheit, die Anzahl der Einheiten und Bemerkungen speichern. Die Einheiten werden als Zahlenwert eingegeben, der sich auf die verknüpfte Tabelle tblEinheiten bezieht.
Bild 2: Beispiel eines Rezeptes im Meal-Master-Format
Die beiden Felder RezeptID und ZutatID dienen als Fremdschlüsselfelder zu den entsprechenden Tabellen. Sie bilden allerdings keinen gemeinsamen Primärschlüssel.
Die Tabelle tblRezepteKategorien
Die Tabelle zur Herstellung der Beziehung zwischen Rezepten und Kategorien ist eine einfache Verknüpfungstabelle mit den Fremdschlüsselfeldern RezeptID und KategorieID zu den Tabellen tblRezepte und tblKategorien.
Die Beziehungen
Die Beschreibung der verwendeten Tabellen enthält bereits die wichtigsten Informationen zu den Beziehungen zwischen den Tabellen. Bild 1 zeigt eine Zusammenfassung der Tabellen und der Beziehungen zwischen den Tabellen. Für alle Beziehungen soll referentielle Integrität bestehen.
Die Eingabe von Test- und anderen Daten ist in der Regel wenig unterhaltsam – zumindest, wenn Sie die Daten stur von einer Vorlage übernehmen müssen.
Daher sorgen Sie nun zunächst einmal für eine Schnittstelle zum Import von bestehenden Daten im Meal-Master-Format.
Hinweis
Zwar ist auch das Erstellen von Schnittstellen nicht gerade beflügelnd, aber deren anschließende Anwendung und die daraus resultierende Zeitersparnis ist ein guter Grund, diese Arbeit in Kauf zu nehmen.
Das Import-Format
Die Dateien mit den Meal-Master-Rezepten sind reine Textdateien. Glücklicherweise haben Sie eine einigermaßen regelmäßige Struktur – was bei einem weltweit verwendeten Format vorausgesetzt werden kann. Die Frage, warum ein solch verbreitetes Format nicht auf dem Stand der Zeit ist – beispielsweise in Form einer XML-Datei -, ist wohl ebenfalls mit der weltweiten Verwendung und der Beliebtheit zu erklären. Je mehr Anwender mit einem Produkt arbeiten, desto mehr Widerstand regt sich gegen die Einführung neuer Standards.
Eine Meal-Master-Datei besteht aus einem oder mehreren Rezepten, die untereinander in die Datei eingetragen sind. Jedes Rezept hat eine fest definierte erste und letzte Zeile. Die erste Zeile beginnt mit fünf großen M oder fünf Minuszeichen (-) und beinhaltet irgendwo dahinter die Zeichenfolge Meal-Master. Die letzte Zeile beginnt ebenso, ist aber nach diesen fünf Zeichen bereits zu Ende.
Dazwischen befinden sich drei Abschnitte: Im ersten, fest definierten Teil stehen Angaben zum Namen des Rezepts, zur Anzahl der Portionen für die angegebene Menge Zutaten und zu den Kategorien, denen das Rezept zugeordnet werden kann.
Im zweiten Teil befinden sich die Zutaten. Die Zutaten werden in ein oder zwei Spalten aufgelistet, wobei feste Bereiche der Zeile für die Informationen Menge, Einheit und Zutat vorgesehen sind.
Der dritte Teil beinhaltet schließlich die eigentliche Anleitung. Bild 2 zeigt ein Beispielrezept im Meal-Master-Format.
Diese Darstellung kann als einfachste Ausführung eines Rezeptes in diesem Format angesehen werden. Umfangreichere Rezepte besitzen weitere Zeilen, die z. B. die Zutaten nach den einzelnen Bestandteilen des Rezeptes aufteilen oder die einfach als Kommentarzeilen – beispielsweise zur Angabe der Herkunft eines Rezeptes – dienen. Solche Besonderheiten spart die im Folgenden erstellte Import-Routine aus Gründen der übersichtlichkeit allerdings aus.
Daten importieren
Function RezepttexteEinlesen(Quelldatei As String) Dim Zeile As String Dim Rezepttext As String Dim Rezeptnummer As Integer Dim Zeilennummer As Integer Dim db As Database Dim rstRezepttexte As Recordset On Error GoTo RezepttexteEinlesen_Err Set db = CurrentDb Set rstRezepttexte = _ db.OpenRecordset("tblRezepttexte", _ dbOpenDynaset) Open Quelldatei For Input As #1 Do While Not EOF(1) Line Input #1, Zeile If (Left(Zeile, 5) = "MMMMM" _ Or Left(Zeile, 5) = "-----") _ And InStr(1, Zeile, "Meal-Master") > 0 Then Zeilennummer = 1 Rezeptnummer = Nz(DMax("Rezeptnummer", _ "tblRezepttexte"), 0) + 1 End If rstRezepttexte.AddNew rstRezepttexte!Rezepttext = Zeile rstRezepttexte!Rezeptnummer = Rezeptnummer rstRezepttexte!Zeilennummer = Zeilennummer rstRezepttexte!EingelesenAm = Date rstRezepttexte.Update Zeilennummer = Zeilennummer + 1 Loop Close #1 Exit Sub RezepttexteEinlesen_Err: If Err.Number = 76 Then MsgBox "Die Datei konnte nicht gefunden " _ & "werden.", vbExclamation + vbOKOnly, _ "Dateifehler" Exit Function Else MsgBox "Fehler: " & Err.Number & " " _ & Err.Description End If End Function
Quellcode 1
Die übernahme von Daten aus Textdateien, die auf anderen Formaten als XML oder CSV basieren, bringt in der Regel Nacharbeit mit sich. Da die Dateien teilweise sehr große Mengen Rezepte enthalten – tausend und mehr sind keine Seltenheit -, soll die Datenbank den Inhalt der Datei zunächst einmal einlesen. Anschließend kann der Anwender dann bestimmen, welche Rezepte er in seine eigene Sammlung aufnehmen möchte.
Für die Zwischenspeicherung der Daten benötigen Sie eine Tabelle namens tblRezepttexte. Die Tabelle speichert die Daten so lange, bis der Anwender sie in seine Sammlung übernimmt.
Die Prozedur aus Quellcode 1 liest die Daten aus der Textdatei zeilenweise in die Tabelle tblRezepttexte ein.
Nach dem Deklarieren und Initialisieren der Objektvariablen öffnet die Prozedur mit der Open-Anweisung die Datei mit dem in dem Parameter Quelldatei angegebenen Namen.
Anschließend liest sie die Datei bis zum Erreichen des Dateiendes zeilenweise ein. Dabei berücksichtigt die Prozedur, ob ein neues Rezept beginnt, und setzt die Variable Rezeptnummer auf den Wert, der um 1 größer als der größte bisher vergebene Wert ist. Die Variable Zeilennummer wird mit jeder Zeile um 1 erhöht.
Beide Variablen werden mit dem Inhalt der Zeile und dem Datum des Einlesens in je einem Datensatz für jede Zeile in der Tabelle tblRezepttexte gespeichert.
Nach dem Einlesen ist kein weiterer Zugriff auf die Datei mehr erforderlich. Von nun an können alle benötigten Informationen zu den einzelnen Rezepten aus der Tabelle tblRezepttexte gelesen werden.
Bild 3: Formular zur übernahme von Rezepten
Die Funktion beinhaltet eine kleine Fehlerbehandlung, die bei Nichtvorhandensein der Datei mit dem übergebenen Namen eine entsprechende Meldung ausgibt.
Daten übernehmen
Der Import von Daten ist mit dem Einlesen der Daten in die Tabelle tblRezepttexte abgeschlossen, da nunmehr kein weiterer Zugriff auf die verwendete Datei mehr erforderlich ist. Im weiteren Verlauf sollen die Daten allerdings noch in das beschriebene Datenmodell übernommen werden. Zur komfortablen Auswahl der gewünschten Rezepte und zur Einleitung der anschließenden Konvertierung der vorhandenen Daten in das Datenmodell verwenden Sie ein geeignetes Formular.
Daten aus einer Textdatei in einer weiter verwertbaren Form in eine Datenbank zu bugsieren, ist keine besondere Kunst. Viel interessanter ist die übernahme der eingelesenen Daten in ein Datenmodell, das aufgrund seiner relationalen Struktur zwar wesentlich komplexer ist als der Ursprung der Daten, aber auch vielfältigere Möglichkeiten bietet.
Nun gilt es, die eingelesenen Daten präzise zu identifizieren und in den entsprechenden Tabellen zu speichern. Für den Komfort des Anwenders ist da – wie üblich – ein Formular erforderlich.
Das Formular soll alle eingelesenen Rezepte in einem Listenfeld anzeigen und die Möglichkeit bieten, per Knopfdruck beliebige Rezepte auszuwählen und in die Datenbank zu übernehmen. Außerdem soll eine Schaltfläche zum Löschen und eine zum Einlesen weiterer Dateien vorhanden sein (siehe Bild 3).
Datei einlesen
Das Einlesen von Dateien sei hier nur in Grundzügen dargestellt: Die Anwendung bietet einen Dialog zur Eingabe der gewünschten Datei an. Der Dialog wird über eine herkömmliche InputBox-Anweisung aufgerufen.
Im Anschluss an die Eingabe des Dateinamens ruft die Prozedur aus Quellcode 2 direkt die Funktion RezepttexteEinlesen auf.
Nach dem Einlesen der Datei aktualisiert die Prozedur die Liste mit den neuen Einträgen per Requery-Anweisung.
Bild 4: Eingabe des Dateinamens
Anzeige der Einträge
Private Sub cmdDateiEinlesen_Click() Dim Dateiname As String Dateiname = InputBox("Bitte geben Sie den Namen der Datei im " _ & "Meal-Master-Format ein.", "Dateinamen eingeben") RezepttexteEinlesen Dateiname Me.lstRezepte.Requery End Sub
Quellcode 2
Bild 5: Die Abfrage
Nicht ganz einfach ist die Anzeige der Rezeptnamen anhand der Daten aus der Tabelle tblRezepttexte. Da die Tabelle alle Zeilen der eingelesenen Rezepte enthält, müssen zunächst jene Zeilen ausfindig gemacht werden, die den Namen des Rezeptes enthalten. Nur diese sind anschließend zu extrahieren.
Bei dieser Aufgabe hilft Ihnen eine Abfrage namens qryRezepttitel. Diese Abfrage verwendet zwei Funktionen, um die gesuchten Informationen in der Tabelle tblRezepttexte zu finden. Die erste Funktion ermittelt alle Zeilen, in denen die Zeichenkette Title: enthalten ist. Sie gibt einen Wert größer 0 für alle entsprechenden Zeilen zurück:
TitelVorhanden: TeilStr(1;[Rezepttext];"Title:")
Die zweite Funktion ermittelt den Titel des Rezeptes in den gefundenen Zeilen:
Titel: TeilStr([Rezepttext];[TitelVorhanden]+7;Länge([Rezepttext])-[TitelVorhanden]+6)
Leider können Abfragen keine Sortierung auf Felder enthalten, die auf die beschriebene Weise ermittelt wurden. Daher benötigen Sie noch eine weitere Abfrage, um die gefundenen Werte zu sortieren. Diese Abfrage basiert auf der soeben beschriebenen Abfrage und sortiert diese nach dem Feld Titel (siehe Bild 6).
Bild 6: Abfrage zur Sortierung des Ergebnisses einer weiteren Abfrage
Diese Abfrage dient schließlich als Datenherkunft für das Listenfeld in dem Formular frmUebernehmen.
Rezept übernehmen
Das übernehmen der Rezepte in das vorliegende Datenmodell ist relativ programmierintensiv. Daher können leider nicht alle verwendeten Prozeduren und Funktionen im Detail vorgestellt werden. Sie erhalten aber in jedem Fall einen überblick über den gesamten Ablauf mit einer Vertiefung zu besonders wichtigen Abschnitten.
Hinweis
Nahezu alle Tabellen der Beispieldatenbank sind mit GUIDs als Primärschlüsseln ausgestattet. GUIDs haben gegenüber herkömmlichen Primärindizes den Vorteil, dass sie sicher einzigartig sind und daher bereits vor dem Abschließen von Datenbankoperationen als Primärschlüsselwert bestimmter Datensätze angenommen und beliebig weiterverarbeitet werden können. Weitere Informationen über diese Art von Primärschlüssel und die Besonderheiten bei deren Verwendung finden Sie im Beitrag Die Geheimnisse der GUID, den Sie im .pdf-Format auf der Heft-CD finden.
Die übernahme eines Rezeptes erfolgt in folgenden Schritten:
Die Steuerung des gesamten Vorgangs erfolgt durch die Prozedur, die beim Betätigen der Schaltfläche Rezept übernehmen des Formulars frmUebernehmen ausgelöst wird.
Diese Prozedur liest sämtliche Informationen in einer Form ein, die weitere Funktionen leicht weiterverarbeiten können.
Ende des frei verfügbaren Teil. Wenn Du mehr lesen möchtest, hole Dir ...
Testzugang
eine Woche kostenlosen Zugriff auf diesen und mehr als 1.000 weitere Artikel
diesen und alle anderen Artikel mit dem Jahresabo