m:n Relation Beispiel. DataSet Regeln erstellen

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 17 Antworten in diesem Thema. Der letzte Beitrag () ist von tragl.

    m:n Relation Beispiel. DataSet Regeln erstellen

    Hallo,

    ich habe 1 Produkt und 3 Eigenschaften Tabellen. Eine letzte Tabelle soll die Eigenschaften den Produkten zuordnen. Jedes Produkt kann mehrere Formen, Farben oder Herkünfte haben.

    Wie muss ich denn jetzt die Verbindungen zu den Primärschlüsseln einstellen? Was bedeutet "nur Beziehung" und was bedeutet "nur Fremdschlüsseleinschränkung". Was benötige ich hier?

    Meistens bastel ich Datenmodelle immer frei Hand ohne Regeln, ich möchte hieran möglichst lernen was regelkonform ist.



    Viele Grüße
    Ich hätte jetzt gesagt, die Tabelle IDs kannst du dir sparen. Du hast eine Tabelle Produkte, darin enthalten sind dann die Fremdschlüssel FormID,HerkunftID und FarbeID, außerdem natürlich noch der Produktname, den hast du ja schon.
    Ich mach immer "Sowohl Beziehungs- als auch Fremdschlüsseleinschränkung" und da ich nicht will, dass wenn ich z.B. eine Form lösche, das Produkt automatisch mit gelöscht wird - mach ich die Löschregel auf None. Dann gibt's nämlich ne Fehlermeldung die
    besagt, dass es ein Produkt gibt, welches den Fremdschlüssel der zu löschenden Form beinhaltet.
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:

    tragl schrieb:

    Ich hätte jetzt gesagt, die Tabelle IDs kannst du dir sparen. Du hast eine Tabelle Produkte, darin enthalten sind dann die Fremdschlüssel FormID,HerkunftID und FarbeID, außerdem natürlich noch der Produktname, den hast du ja schon.
    naja, HDZ will seine Produkte ja mit mehrern von allem ausstatten - also ein Produkt soll sowohl Rund als auch eckig sein können.

    Haudruferzappeltnoch schrieb:

    Jedes Produkt kann mehrere Formen, Farben oder Herkünfte haben.
    IDs als Name einer ZuordnungsTabelle findich komisch.
    Auch komisch die vierfachen Zuordnungen.
    Das bedeutet ja, wenn ein Produkt rund und quadratisch ist, dann muss es auch mehrere herkünfte haben und Orte und Farben.
    Und ein Produkt hat immer genausoviele Herkünfte und Farben, wie es Formen hat - also komisch, was da modelliert ist.
    tragls Ansatz ist da schon plausibler, auch wenn HDZs Anforderung dadurch nicht erfüllt ist.
    Ich täte eher mehrere Zuordnungstabellen vorschlagen, vlt. eine für Form, eine für Farbe, etc..
    Auch Mischformen von meim und tragls Ansatz fände ich plausibel: Also wenn ein Produkt nur genau eine Herkunft haben kann, dann die HerkunftId gleich im Produkt anlegen.

    Jedenfalls würde mein Vorschlag "Je Entität eine eigene Zuweissungstabelle" auch die Benamung erleichtern: ProduktForm, ProduktHerkunft statt IDs

    Ansonsten ist Löschweitergabe für mich das "natürliche" Verhalten - also wenns die Farbe Rot nicht mehr gibt, dann gibts auch keine Produkte mehr in dieser Farbe.
    Wenn Löschen verboten ist, dann lösch ich eben nicht.
    Aber damit sagich nix gegen die Massnahme - damit kann man gut das Ziel "LöschProtektion" erreichen.
    Ich bin halt mehr in SpielProjekten unterwegs, da ist öfter mal erwünscht, auch von "Stammdaten" mal was löschen zu können.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „ErfinderDesRades“ ()

    Ok ich denke so meintest du das:



    Ich nutze SetDefault, mit dem Gedanken, dass wenn ich eine Farbe lösche, dann geht dem Produkt die Farbe verloren, das Produkt bleibt aber da.

    Was sind denn genau die Fremdschlüssel und Beziehungseinschränkungen?
    Was passiert wenn AutoIncrement eingestellt ist und ein Eintrag gelöscht wird? Wird das AutoIncrement aktualisiert oder bleibt da eine Lücke?
    Kann ein Produkt ohne Farbe existieren? Ist es dann unsichtbar? Oder ist die Farbe undefiniert? Was passiert, wenn die Farbe des Produktes dann abgefragt oder angezeigt werden soll?

    Haudruferzappeltnoch schrieb:

    Was passiert wenn AutoIncrement eingestellt ist und ein Eintrag gelöscht wird? […] bleibt da eine Lücke?
    Ja. Die ID wird dann auch nicht neu vergeben. Das ist (wohl) so beabsichtlicht. Denn wenn Produkt X auf die Farbe Rot mit der ID 42 verweist und Rot wird gelöscht und dann wird Pink hinzugefügt und bekommt die nun unbesetzte ID 42, dann ist Produkt X plötzlich pink.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Da musst Du aber aufpassen, was Du im tDS als DefaultValue einstellen kannst. Die Farbe scheint ja kein simpler Wert, sondern ein Tabelleneintrag zu sein. Den zu ersetzen könnte schwierig werden. Oder willst Du eine Art DefaultFarbe machen, dessen ID Du als NullValue dann bei Produkt setzen willst?
    Also ID = 0, Name = "keine". Und dann bei Produkt -> FarbID: NullValue = 0

    btw: jede Tabelle sollte ne Spalte ID mit AutoIncrement haben. Wenn sie keine Abhängigkeiten zu anderen Tabellen hat, belass es wirklich beim Namen ID, nicht wie OrtID in der Tabelle Herkunft, solange Du keine Tabelle Ort hast, auf die die Herkunfts-Tabellenzeile dann verweist.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

    Haudruferzappeltnoch schrieb:

    dass wenn ich eine Farbe lösche, dann geht dem Produkt die Farbe verloren, das Produkt bleibt aber da.
    Das wird sich in deinem Datenmodell auch so ereignen, da deine Farben über eine Zuordnungstabelle modelliert sind.
    Meine Aussage war wohl irreführend, weil sie ein Modell vorraussetzte, wo ein Produkt nur eine farbe hätte.
    Also alles gut: In deim Modell verschwinden bei Löschweitergabe "nur" alle Zuordnungen dieser Farbe zu den Produkten - die Produkte bleiben bestehen, und behalten auch ihre anderen Farben - wenn vorhanden.

    Jo, mit DeleteAction.SetDefault habich noch nie rumgespielt. Ich vermute, dass setzt bei Löschung einer ParentRow den FK einer ChildRow auf was für die FK-Spalte als DefaultValue eingestellt ist - wenn da nichtss eingestellt ist also auf DbNull.
    Wird natürlich krachen.
    Und ebenso wird krachen, wenn als DefaultValue für den FK was ungültiges eingestellt ist.
    Kann eine Massnahme sein, um etwas zu erreichen - sehe ich aber noch weniger als das typische Verhalten an als DeleteAction.SetNull (wo's dann immer kracht, weil eben das erwünscht ist).
    Kommt sicher auf den Anwendungsfall an. Bei mir wäre das so gelöst, dass wenn es eine Farbe nicht mehr gibt dann schalte ich sie auf Aktiv = False (Aktiv ist dann eine Bolean-Spalte in der Tabelle), sodass sie keinem Produkt mehr zugeordnet werden kann (im Produkt-Edit/Neu-Dialog hat die Bindingsource für Farbe einen Filter „Aktiv = True“). Wenn alle Produkte mit der Farbe abverkauft sind dann erst das Produkt löschen, danach endgültig die Farbe. Oder aber aus archivierungsgründen das Produkt auch auf inaktiv setzen -> man kann dann trotzdem noch z.B. die Verbräuche oder was auch immer jederzeit einsehen.
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:

    tragl schrieb:

    schalte ich sie auf Aktiv = False
    Jo, das ist bei uns auf Arbeit auch der übliche "Lösch-Ersatz" - oder wir setzen ein UngueltigAb-Datum.
    Da gehts ja auch um rechtsverbindliche Vorgänge - da ists keine Option, die Daten wirklich zu löschen, sodass der vorgang für die DB quasi nie stattgefunden hat.
    Gibt es in diesem Datenmodell eine Möglichkeit in einer Auswahl an Produkten gemeinsame Eigenschaften zu zählen?

    Ich habe zum Beispiel eine Liste mit 5 Produkten, jetzt könnte ich in der Produktfarbe die FarbIDs filtern, gibt es eine LINQ Syntax die sowas erlaubt:
    MSSQL:

    Quellcode

    1. Select * from ProduktFarbe where ProduktID in (PID1,PID2,PID3,PID4,PID5)
    in vergleicht mit jedem Wert in dem Array

    Mit ganz vielen OrElse geht natürlich aber man weiß ja nicht immer wie viele man braucht
    Kannst Du mal bitte konkreter werden, da der Satzbau gerade für mich viele Fragezeichen hinterlässt und ich daher nicht weiß, was das Ziel ist.
    Du hast 5 Produkte und willst von denen … was genau? Wieviele unterschiedliche Farben es gibt?
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

    Haudruferzappeltnoch schrieb:

    Gibt es in diesem Datenmodell eine Möglichkeit in einer Auswahl an Produkten gemeinsame Eigenschaften zu zählen?

    jo du könntest die Produkte gefiltert nach Farbe z.B. in nem DataGridView anzeigen lassen und die Rows zählen bzw. die Anzahl der Rows in einem BindingCompleted-Eventhandler in z.B. einem Label o.ä. ausgeben lassen


    Das mach in fast jedem DataGridView bei mir in einem StatusStrip.

    VB.NET-Quellcode

    1. Private Sub dgv_DataBindingComplete(sender As Object, e As EventArgs) Handles dgvStandort.DataBindingComplete
    2. dgvStandort.totalRowsCount(tssGesamt)
    3. End Sub
    4. Private Sub dgv_SelectionChanged(sender As Object, e As EventArgs) Handles dgvStandort.SelectionChanged
    5. dgvStandort.selectedRowsCount(tssMarkiert)
    6. End Sub


    Um an die Namen der Farben zum Filtern dran zu kommen, könntest du dir codeseitig oder im dataset-designer entsprechende expression-columns dranheften, die dir den Namen ausgeben.
    Edit:

    Also du hast die Tabelle Produkt und die Tabelle Farbe. In Produkt gibt's eine FarbeID. Dann fügst du dort eine FarbeName-Expression hinzu:

    VB.NET-Quellcode

    1. Dts.Produkt.Columns.Add("expFarbeName", GetType(String)).Expression = "Parent(FK_Farbe_Produkt).FarbeName")


    und die kannst du dann codeseitig als Bindingsource-Filter setzen: bs.Filter = "WHERE expFarbeName = gelb"

    Edit2:
    Alternativ in z.B. einer RichTextBox alle Farben und Anzahl Produkte ausgeben lassen, geht natürlich auch

    VB.NET-Quellcode

    1. For Each Farbe in Dts.Farben
    2. Richtextbox.AppendText = $"Farbe: {Farbe.FarbeName} | Anzahl Produkte: {Dts.Produkte.Where(Function(x)x.FarbenRow = Farbe).Count}"
    3. Next

    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „tragl“ ()

    Ich glaub da gehört bei dem LINQ-Statement ein Is rein: Dts.Produkte.Where(Function(x) x.FarbenRow Is Farbe).Count
    Man kann auch mit GroupBy arbeiten, um eine gruppierte Liste zu erhalten.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

    Haudruferzappeltnoch schrieb:

    gibt es eine LINQ Syntax die sowas erlaubt:

    SQL-Abfrage

    1. Select * from ProduktFarbe where ProduktID in (PID1,PID2,PID3,PID4,PID5)
    jo, gibbets:

    VB.NET-Quellcode

    1. dim farben = ProductFarben.Where(Function(x){PID1,PID2,PID3,PID4,PID5}.Contains(x.ProductID))
    Das Problem ist vielleicht sogar eher, dasses was du vorgibst, in SQL kaum möglich ist - nur in StoredProcedures etc..

    VaporiZed schrieb:

    Ich glaub da gehört bei dem LINQ-Statement ein Is rein:

    jo stimmt, danke - hatte ich grad ausm Kopf reingetickert und hatte keine IntelliSense zur Hand :P
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:
    In Mysql und mssql gibt es das mit in als art vergleichsoperator

    VaporiZed schrieb:

    Kannst Du mal bitte konkreter werden, da der Satzbau gerade für mich viele Fragezeichen hinterlässt und ich daher nicht weiß, was das Ziel ist.
    Du hast 5 Produkte und willst von denen … was genau? Wieviele unterschiedliche Farben es gibt?
    Was ich machen wollte: Eine Sammlung aus 5 Produkten nehme ich her.
    Mit dem Filter Where(Function(x) SammlungArr.Contains(x.ProductID)) bekomme ich nun alle vorhandenen Farben, die in meiner Sammlung vorkommen, und sie kommen mehrfach vor wenn verschiedene Produkte gleiche Farben haben.
    Dadurch kann ich durch nachzählen herausfinden welche Farben mehrfach vorkommen -> also eine Gemeinsamkeit bestimmen. In etwa ErgebnisFarbenAusSammlung.Where(Function(x) x.FarbID = n).Count > 1
    Könntest dir auch ein Parent->Child-View bauen, dann klickste in einem DGV auf die Farbe und im anderen bekommst du die Produkte angezeigt, die die Farbe besitzen
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup: