Ankündigung

Einklappen
Keine Ankündigung bisher.

Guid als PK von verschiedenen Tabellen referenzieren.

Einklappen
X
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • Guid als PK von verschiedenen Tabellen referenzieren.

    Hallo zusammen!

    Ich versuche gerade eine DB zu Designen (unabhängig jetzt von der RDBMS, in meinen Testszenarien SQLite oder MariaDB). Es geht dabei um ein Restaurant-System bzw. eine App für Kellner (also eigentlich nichts Aufregendes). Allerdings bin ich dabei auf eine Hürde gestoßen, wo ich nicht genau weiß, wie ich sie lösen soll oder ob ich vielleicht hier sogar versehentlich ein Anti-Pattern implementiere.

    Folgende Tabelle (grob aus dem Kontext genommen und auf das wesentliche reduziert), alle PK sind fortlaufende int's:

    - Menu (Beinhaltet Name eines Menüs, die Kategorie Essen/Trinken/Kuchen/(was auch immer) sowie den Preis,
    - MenuSize (Beinhaltet die verschiedenen Menü Größen die bestellt werden können, Beispiel: Normal, Klein, 0,25L, 0,5L, 1/8L, ...)
    - MenuExtras (Beihaltet Extras die zu einem Menü dazu bestellt werden können, Beispiel "extra Grüner Salat", Extra Knödel, ohne Salat)
    - MenuPossibleSizes (Beinhaltet die verfügbaren Größen für ein Menü und deren Preisdifferenz - beispiel: wenn man klein für Schnitzel bestellt wird der Preis um 1€ billiger)
    - MenuPossibleExtras (Beinhaltet Extras, die für ein Menü bestellt werden kann, ebenfalls mit Preisdifferenz- Beispiel: extra Salat = 1€ mehr, ohne Knödel = 1€ billiger)

    "Order Aggregate" - wobei hier der Pattern nicht wirklich gilt da ja eher auf Domain Model bezogen und nicht auf Datenbank Model
    - Order (hier wird einfach Bestellnummer und Tischnummer, Kellner, Priorität (Reihenfolge der Abarbeitung), etc. gespeichert)
    - OrderItem (Menu Detail mit Endpreis, Größe, die Auswahlen werden als Text zusammengefügt "Cola 0,25L mit Zitrone", Anzahl und wieviel noch unbezahlt sind bzw. noch nicht geliefert wurden. Es kann auch eine sogenannte "Sonderbestellung" beinhalten, die keine Referenz auf ein vordefiniertes Menu hat, Bsp. „Knoblauchsuppe“ obwohl es im Menü nicht vorgesehen ist...)
    - OrderItemExtras (beinhaltet Referenzen zu den Extras von einem Order Item)
    - OrderItemMixedWith (beinhaltet Referenzen zu gemischten Produkten. Beispiel: Kunde will Cola mit Mineral, in diesem Fall ist das Hauptmenu ein "Cola" und es wird in der Tabelle MixedWith eine Referenz auf das Menu "Mineral" gehalten

    Soweit so gut, das ganz ist in Ordnung und funktioniert. Ich möchte jeder aber einen Status der Verfügbarkeit hinzufügen. Also "Verfügbar", "Verspätet" und "Aus". Zusätzlich vl. bei einem Menü hinterlegen, das nur 100 Stück Schweinsbraten vorhanden sind, und danach "verspätet" oder "aus" ist, je nach dem.

    Meine erste Überlegung war, bei Menu, MenuExtras und OrderItem (für Sonderbestellungen) folgende Attribute hinzuzufügen:

    - Status
    - AmountAvailable

    Auf diese Weise werden aber die Querys extrem kompliziert, wenn ich im "Ausgabesystem" feststellen will, welche Bestellung als nächstes dran ist, die auch gemacht werden kann bzw. teilweise abgearbeitet werden kann. Ich muss OrderItem prüfen ob Verfügbar, Joine Menus über OrderItemMixedWith und MenuExtras über OrderItemExtras. Und das alles nur um 1 OrderItem abarbeiten zu können, wo es möglich ist.

    Jetzt hatte ich als alternative folgende Idee: Statt int’s als PK verwende ich Guid’s. Ich erstelle nur 1 Tabelle namens „AvailabilityStatus“ mit 3 Attributen
    • Id PK
    • Status
    • AmountAvailable

    Statt diese Attribute in 3 Tabellen aufzuteilen verwende ich nur eine. Id entspricht dem Guid des Menus, Extras bzw. Orderitem. Dadurch brauche ich nur 1 Tabelle Joinen und prüfen. Hier kann ich simple überprüfen mit IN (Liste der Guid)

    Statt OrderItemExtras und OrderItemMixedWith auch nur 1 Tabelle namens „OrderItemAvailability“ die nichts Anderes macht als eine Liste der Guid zu speichern, die für diese Bestellung relevant sind. Es ist der Tabelle wurscht ob Menu, MenuExtra oder OrderItem.

    Nun meine Frage: Sieht hier wer ein Problem bzw. evtl. Anti-Pattern, wenn ich in einer Tabelle Guid’s als PK verwende, die in verschiedenen anderen Tabellen bereits als PK vorkommen? Ich kann anhand der Guid nicht identifizieren woher die Referenz ursprünglich kommt (müsste in 3 Tabellen suchen wo sie existiert) aber das ist mir ja egal da ich das in diese Richtung nicht brauche.

    Ich hoffe ich hab mir verständlich ausgedrückt…


  • #2
    Ob ein PK eine GUID ist oder nicht, ist dem PK egal.
    Ein PK ist ein PK, ungünstige wäre lediglich ein BLOB als PK, ist vielleicht auch bei den meisten Systemen gar nicht erlaubt.

    Referenzen in einem Feld als Liste zu halten, finde ich problematisch, weil die Verwaltungswerkzeuge dafür in SQL nicht gut geeignet sind. Ein paar ID in ein Feld zu klatschen ist nicht so ein Drama, aber sie wieder zu löschen bei Bestelländerung oder Reports darüber zu fahren ist eher nicht so schön. Solche Sachen gehen Richtung noSql und haben vielleicht auch ihre eigene Daseinsberechtigung (s.u).

    Zu Deinem "Antipattern" Problem:
    Dein Datenmodell sieht so aus, als ob es nach und nach entstanden ist. Erst waren da die Menus, dann gab's Extras und dann kam noch eine ganz abgedreht Marketingaktion dazu. Was kommt wohl als nächstes? Ich würde sagen, Du kommst mit Deiner Befürchtung zu spät, das Kind ist schon in den Brunnen gefallen.

    Ich seh das so. Eine Bestellung bedeutet am Ende immer, ich hab x Sachen in der Tüte. Die Sachen kann ich aufschreiben, untereinander, in eine Liste. Kleine Anmerkung aus dem Alltag, (Bestell-)Listen treten niemals in Form von Bestellzeilen auf, weder sprachlich noch real. (Einen chaotischen Einkaufszettel nehme ich mal aus)

    Welche bekloppte Marketingaktion oder Idee vom Chef dazu geführt hat, dass etwas auf der Bestell-Liste landet, ist ab dem Zeitpunkt, wo das Teil auf der Liste steht (fast) egal.

    Was Du also neben dieser Liste (Deine Orderitems ungefähr) verwalten und abbilden musst, ist ein möglichst generisches Modell von Produkt-Bundles( und Produkttypgruppen), Optionen, Rabatten und deren Abhängigkeiten untereinander, letzteres wird im Datenmodell z.B. häufig mit Selbstreferenzen gelöst. Darauf aufbauend kommt dann die Implementierung für den Bestellvorgang, der ein ausgewähltes Produkt in die Orderitems einfügt.Nicht zu vergessen der umgekehrt Weg bei Bestelländerung. Dabei ist je nach Komplexität zu prüfen, ob mit der Entfernung von Orderitems auch Bedingungen für andere Orderitems wegfallen.
    Du willst ja am Ende möglichst flexibel Bestellungen annehmen können, ohne jedes Mal die App neu zu schreiben.

    Bei der Modellierung des Produkt-Teils kann man vielleicht etwas in die noSQL Kiste greifen und mögliche Gruppierungen, Optionen und Abhängigkeiten mit JSON Feldern (Arrays, Aufzählungen..) abbilden. Hier hat man jedenfalls ein hohes Maß an Flexibilität, das man mindestens dann gut einsetzen kann, wenn die betroffenen Daten nicht verarbeitet werden, keine Kernworkflows betreffen, sondern eher durchgereicht werden. (bspw. Art des Spielzeugs in der Kiddy Box)

    Einfach mal durchdenken wie man Dein Modell verbessern kann und zurückmelden.

    Kommentar


    • #3
      Du solltest versuchsen zu abstrahieren. Du hast hier offensichtlich die Begriffe die bei der Erörderung der Anforderungen gefallen sind 1:1 als Model abgbildet. Das ist nicht unbedingt sinnvoll. Was unterscheidet z.B. OrderItem, OrderItemExtras, OrderItemMixedWith derartig, dass getrennte Datenstrukturen nötig sind? Für mich sieht das alles wie eine OrderItem aus, nur dass einige davon in Bezug stehen können.
      Selbes bei Menu und MenuExtra. Wenn du das Vereinheitlichst, dürfte das an der Stelle um einiges einfacher werden und die Komplexität reduzieren.
      Die Verfügbarkeiten kannst du dann in "Menu" oder einer extra Datenstruktur abbilden (auf Ebene von "Menu" hast du ein Problem, wenn die Limitierung auf Basis einer Zutat erfolgt, die in mehrere Menüs vorkommt.).

      Zitat von munzili Beitrag anzeigen
      Auf diese Weise werden aber die Querys extrem kompliziert, wenn ich im "Ausgabesystem" feststellen will, welche Bestellung als nächstes dran ist, die auch gemacht werden kann bzw. teilweise abgearbeitet werden kann. Ich muss OrderItem prüfen ob Verfügbar, Joine Menus über OrderItemMixedWith und MenuExtras über OrderItemExtras. Und das alles nur um 1 OrderItem abarbeiten zu können, wo es möglich ist.
      Was bei der Problemstellung aber auch eigentlich völlig wurscht ist. In der Dimension kommst du auch davon, wenn du das alles in den Speicher lädst und dort zusammenführst.

      Kommentar


      • #4
        Vl. hab ich teilweise wirklich einen Knopf im Hirn aber ich versuch mal die Anforderungen zu ergänzen (habs ja natürlich nur aufs nötig runter gebrochen gehabt, war vl. zu wenig ). Das ist der IST-Stand. Ich versuche gerade ein Refactoring der Tabellen um Querys zu vereinfachen (daher auch die Idee mit AvailabilityStatus) bzw. generell ein gute Struktur zu schaffen. Das ganze ist ein Hobby-Projekt (kein Chef, Marketingabteilung oder so . ). Es geht dabei um ein System für Vereine, Feste, Frühschoppen oder ähnliches. Die Menüs ändern sich oft komplett da verschiedene Feste.

        - Zuerst Menu: Es gibt da folgende Anforderung (ich hoffe ich vergesse nichts) bzw. noch mehr Tabellen die zu erwähnen sind.
        -- Es gibt Menü Typen (Tabelle MenuType) Dort gibt es Felder Id, Name, Tax(Steuer), Mixable
        Mixable definiert, ob Menüs von diesem Typen gemischt werden können (beispiel Getränke). Könnte aber auch "Zigaretten" sein, auch das wird verkauft.
        -- Es gibt Menü Gruppen (Tabelle MenuGroup mit den Felder: Id, MenuTypeId, Name)
        -- Es gibt Menü mit den Felder Id, MenuGroupId, Name, Price, Availability, AvailabilityAmount
        -- Es gibt Extras zu Menüs (MenuExtra) die definiert werden können. Unterschied zu Menü: Ein Menü kommt 1 mal vor, Extras können zu mehreren Menüs zugeordnet werden und MenüPreis soll angepasst werden (oft eine Diskussion bei Festen von Kellner die das ja auch nur Hobbymäßig machen, wie viel soll verrechnet werden wenn dies und das mehr bestellt wird oder weniger). Kann somit im vorhinein definiert werden. Im Restaurant sind Mitarbeiter die das Täglich machen und bereits wiesen was der Unterscheid ist, diese Helfer kommen aber vl. erst in der Früh, erfahren dort alles und sollen Preise auswendig wiesen und das noch bei Sonderwünschen. Hier tauchen dann oft diese Fragen bei Organisatoren-Team auf "was kann ich verlangen". So ist das direkt gelöst.
        -- Es gibt Menü Größen, ebenfalls mit definierten Preisanpassung aus gleichem Grund wie bei Extras. Menü kann gewisse Größen haben, Größen können aber bei mehrere Menüs verwendet werden.

        Es stimmt schon, ich könnte Menü in einer Tree-Struktur speichern mit einer Selbstreferenz. Allerdings wäre dein bei jeder Menü Group, Type oder Menü auch immer ein Preis, Verfügbarkeit, Steuersatz, Mixable zu definieren was ja so nicht stimmt. (Steuersatz soll auf der Gruppe definiert werden, nicht pro Menü, eine Gruppe hat keinen Preis, ...) Und es wird immer nur diese 3 Stufen geben.

        Bezüglich Order, OrderItem etc. . Ich brauche OrderItemExtras, OrderItemMixedWith damit ich die Verfügbarkeit referenziert habe. Ich brauch irgendeine Referenz zu den Verfügbarkeiten der Menüs. Die Orders werden row für row abgearbeitet. Das System soll Order suchen, wo irgendwas abgearbeitet werden kann. Erst wenn das erledigt ist, kommt der nächste. Dazu wird im Order ein Lock Mechanismus verwendet (der Order wird für einen User gesperrt bis fertig). Ein Bestellung kann die Extras "extra Salat" und "extra Knödel" beinhalten und ich muss wiesen das beide auch verfügbar sind bei der Ausgabestelle.

        Jetzt kann in einer Order sein das 2 Schnitzel und 1 Schweinsbraten bestellt sind. Die "Ausgabestelle" sieht das auf einem Tablet. Jetzt ist aber nur 1 Schnitzel verfügbar, die anderen dauern noch 10 min bis fertig. Die Ausgabestelle setzt das Menü (oder auch das Extra was dazu bestellt worden ist) auf nur mehr 1 verfügbar. Das System check das in der Bestellt und passt die Übersicht an, so das 1 Schnitzel und 1 Schweinsbraten angezeigt wird. Diese Bestellung wird weggeschickt. In der Zwischenzeit können weitere Bestellungen abgearbeitet werden. Sobald Schnitzel wieder verfügbar sind, werden die noch offenen Bestellungs-Einträge zuerst abgearbeitet, bevor wieder andere Bestellungen dran genommen werden in der Queue.

        Daher mein Gedanke des Zusamenführen der Status auf AvailabilityStatus. Die PK wäre eine FK, die aber pro row von wo anders kommt (in der 1 row von Menu FK, in der 2 row von MenuExtra FK, die 3 row FK von Menu, ...) Mir ist ja egal woher die Verfügbarkeit kommt, ich brauch nur den Status. Wenn ich also nur die Guid's referenziere, wäre das alles einfacher darzustellen bzw. die Querys einfacher und effizienter.

        Nur die grundlegende Frage: ist die Idee, das jeder Eintrag in AvailabilityStatus den FK von einer anderen Tabelle hat eine gute Lösung? Oder ein Anti-Pattern? Ich hab hier halt Bauchweh da ein FK Feld eindeutig sein sollte woher es kommt. Andererseits brauche ich diese Information in diese Tabelle auch nicht da der Guid eindeutig im System ist und ich diese von außen Referenziere, nicht umgekehrt.

        Ich hoffe, jetzt ist das ganze ein bischen klarer

        Kommentar

        Lädt...
        X