Neuer Datensatz in ParentTable erstellen und sofort Datensatz aus ChildTable koppeln

  • VB.NET

Es gibt 19 Antworten in diesem Thema. Der letzte Beitrag () ist von T-BoneSteak.

    Neuer Datensatz in ParentTable erstellen und sofort Datensatz aus ChildTable koppeln

    Hallo zusammen, ich arbeite mit einem Dataset das aus zwei Tabellen besteht. Diese stehen in einer Beziehung zueinander. Parent -> Table1 und Child -> Table2. Nun füge ich eine neue ROW in Table1. Diese erhält zunächst ID -1 was ja auch vollkommen korrekt ist. Füge ich eine weitere ein erhält diese ID -2 usw. Nun meine Frage: Ist es möglich eine Row in Table2 einzufügen und einen Verweis auf die frisch erstellte Row mit ID -1 zu machen. Wenn ich Table1 vorher update in die Datenbank, erhält sie die passende ID und alles ist kein Problem. Wollte nur wissen ob es auch eine Möglichkeit gibt die Beziehung vor dem Update herzustellen.
    Es hängt davon ab, wer die ID erstellt.
    Wenn die DB die ID beim Einfügen selbst erstellt (Table Auto-Increment o.ä.)
    dann muss man diese wieder auslesen und in der Referenz nutzen.
    Wenn man die ID selber vergibt, wird es funktionieren, sofern man steuern kann,
    in welcher Reihenfolge die Updates an die DB gesendet werden. Steht da die falsche
    Reihenfolge drin, kommt es zu schwer lokalisierbaren Fehlern.

    Ich nutze das Entity Framework, das kommt mit beiden Varianten gut zurecht.
    An manchen Tagen gibt es zu allem Überfluss auch noch Ärger!

    VB1963 schrieb:

    brauchst du nicht, die ID wird in Tabelle2 automatisch generiert, da solltest du gar nichts machen müssen...


    Die ID für den Datensatz in Tabelle2 wird automatisch generiert, aber ich muss ja die ID des Datensatzes aus Tabelle1 angeben, auf den der Datensatz aus Tabelle2 verweist.


    Rainman schrieb:

    Es hängt davon ab, wer die ID erstellt.
    Wenn die DB die ID beim Einfügen selbst erstellt (Table Auto-Increment o.ä.)
    dann muss man diese wieder auslesen und in der Referenz nutzen.


    Ja dies ist der Fall. Aber wie kann ich die ID auslesen? Die ID wird ja erst beim Update erstellt :S


    Hier mal etwas Code:

    VB.NET-Quellcode

    1. Module Module1
    2. Sub Main()
    3. Dim mDS As New DS
    4. Dim typA As New DSTableAdapters.f_typenTableAdapter
    5. Dim traA As New DSTableAdapters.tra_f_typenTableAdapter
    6. 'mDS.Relations.Add(New DataRelation("rel", mDS.f_typen.ftyp_idColumn, mDS.tra_f_typen.tra_to_ftyp_idColumn))
    7. typA.Fill(mDS.f_typen)
    8. traA.Fill(mDS.tra_f_typen)
    9. ' Dim typR As DS.f_typenRow
    10. Dim typR = mDS.f_typen.Newf_typenRow
    11. 'typR.ftyp_id = xxx '## Primary Key Autoinc
    12. typR.ftyp_timestamp = Now
    13. typR.ftyp_history = "so ebes"
    14. typR.ftyp_title = "Kopf"
    15. typR.ftyp_type = "8"
    16. mDS.f_typen.Addf_typenRow(typR)
    17. 'Dim traR As DS.tra_f_typenRow
    18. Dim traR = mDS.tra_f_typen.Newtra_f_typenRow
    19. traR.tra_timestamp = Now
    20. traR.tra_language = "en"
    21. traR.tra_title = "head"
    22. 'traR.tra_to_ftyp_id = xxx '### hier soll die ID vom eingefügten Satz aus f_typen stehen
    23. traR.tra_history = ""
    24. traR.SetParentRow(typR, mDS.Relations("FK_tra_f_typen_f_typen"))
    25. 'mDS.Relations.Add(New DataRelation("FK_tra_f_typen_f_typen", mDS.f_typen.ftyp_idColumn, mDS.tra_f_typen.tra_to_ftyp_idColumn))
    26. mDS.tra_f_typen.Addtra_f_typenRow(traR)
    27. typA.Update(mDS.f_typen)
    28. traA.Update(mDS.tra_f_typen) '#### hier Fehlermeldung
    29. End Sub
    30. End Module

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „T-BoneSteak“ ()

    Geht leider immer noch nicht. Aber warum sollte man zuerst die ChildTable updaten? ich dachte wenn dann die Parent zuerst ?( Selbst wenn ich es mit einem Updatemanager mache funktioniert es nicht. Hier mal die Fehlermeldung:
    Ein Ausnahmefehler des Typs "System.Data.SqlClient.SqlException" ist in System.Data.dll aufgetreten.

    Zusätzliche Informationen: Die INSERT-Anweisung steht in Konflikt mit der FOREIGN KEY-Einschränkung 'FK_tra_f_typen'. Der Konflikt trat in der eepa-Datenbank, Tabelle 'dbo.f_typen', column 'ftyp_id' auf.

    guck dir erstmal das typisierte Programmieren eines Datasets an.
    Wenn das Dataset richtig konfiguriert ist, dann kan ühaupt keine ChildRow geadded werden, ohne dass diese korrekt auf eine ParentRow verweist.

    gugge vier Views-Videos - coden in typisierter Manier.

    Prinzipiell ist auch das Updaten der DB kein Problem, jedenfalls bei SqlServer generiert der Connector die richtigen Commands.

    Aber ich rate dir erstmal ab, bei deinem Kenntnisstand gleich eine DB zu hinterlegen, denn du hast eh noch jede Menge Stoff zur Einarbeitung, und wirst auch dein Modell noch öfter ändern müssen - allein deine gräßliche Benamung - du wirst doch nicht für immer mit solchen Monstrositäten arbeiten wollen:

    VB.NET-Quellcode

    1. mDS.tra_f_typen.Addtra_f_typenRow(...)
    Was soll denn ein tra_f_typen sein - da muss sich doch ein aussagekräftigerer und praktischerer Name für finden lassen?

    ErfinderDesRades schrieb:

    guck dir erstmal das typisierte Programmieren eines Datasets an.
    Wenn das Dataset richtig konfiguriert ist, dann kan ühaupt keine ChildRow geadded werden, ohne dass diese auf eine ParentRow verweist.


    Jawoll das ist nicht möglich. Vielleicht drücke ich mich auch nicht verständlich aus.. Meine momentane Vorgehensweise wenn ich neue Datensätze einfüge ist es zuerst den Datensatz in der ParentTable einzuüfen. Dann mache ich ein Update der Parenttable. Somit erhält der neue Datensatz eine ID. Anschließen füge ich einen neuen Datensatz in der Childtable ein und schreibe in die Spalte mit dem Verweis auf die ParentTable die neue ID. Zum Schluss update ich die ChildTable.
    Wenn ich jetzt jedoch nach dem Einfügen des Datensatzes in die ParentTable kein Update mache steht dort die -1 in der ID-Spalte. Diesen Wert kann ich der ChildTable aber nicht als Verweis geben, da ja die -1 beim Update abgeändert wird.

    Und zu der Namesgebung.. Ja das ist ein echter Exot :D tra steht für translation, weil dort eine Fremdsprache eingefügt wird und das f steht für einen Katalog.. Aber tut hier ja auch nichts zur Sache

    T-BoneSteak schrieb:

    Wenn ich jetzt jedoch nach dem Einfügen des Datensatzes in die ParentTable kein Update mache steht dort die -1 in der ID-Spalte. Diesen Wert kann ich der ChildTable aber nicht als Verweis geben, da ja die -1 beim Update abgeändert wird.
    Wenn der TableAdapterManager richtig funktioniert ist das alles kein Problem.

    Es ist nicht erforderlich, im Dataset zugefügte DataRows einzeln auch noch an die DB zu schicken.
    Das Dataset verfügt über eine Änderungsverfolgung, und ein TableAdapterManager kann anhand dessen jederzeit Dataset und Datenbank in Übereinstimmung bringen.
    Egal, ob da nun in einer Tabelle ein Datensatz geändert wurde, oder ob da in 10 Tabellen hunderte von DS zugefügt, geändert, gelöscht wurden. Und auch egal, ob und wie diese Tabellen miteinander in Beziehung stehen. Und insbesondere egal, welche Werte deren IDs haben.
    Bei richtiger typisierter Programmierung wirst du die Id-Spalten niemals überhaupt anfassen.
    Ja das habe ich auch verstanden. Aber wie kann ich dem neu erstellten Child Datensatz sagen, dass er der Child von dem neu erstellten Parent Datensatz ist? Ich muss ja da irgend eine Verbindung herstellen.. Sagen wir ich habe im Parent Table 100 Datensätze und im Child Table 50 nun erstelle ich im Parent Table den 101. Datensatz und im Child Table den 51. Datensatz.. Woher weis der 51. dass er zum 101. gehört? Dies ist mir total unklar
    Ich habe versucht mich an das Video zu halte. Jedoch bei der Zeile

    VB.NET-Quellcode

    1. Dim rwCatNew = FourViewsDts.Category.AddCategoryRow(rwCat.Name)

    Muss ich in den Klammern eine typisierte Datarow angeben. lasse ich das .Name weg wird der Teil hinter dem = unterstrichen, da der Ausdruck keinen Wert ergibt.. Was tun?

    T-BoneSteak schrieb:

    Muss ich in den Klammern eine typisierte Datarow angeben.
    Nein! keine typisierte Datarow angeben!

    In den Videos sage ichs zwar immer, aber jetzt nocheinmal: Es gibt immer 2 Add-Methoden: die eine erwartet eine typisierte Row, die nimmste besser nicht.
    Die andere Überladung erwartet alle Werte, die zum Bilden der Row erforderlich sind, und bildet sie dann.
    Diese 2. Überladung nimmste.
    Was eine Überladung ist: Grundlagen: Fachbegriffe
    Die Add-Methode aus deim geposteten Snippet braucht nur einen String, um eine CategoryRow zu bilden. Den bekommt sie auch, denn rwCat.Name ist ja ein String.
    Was deine typisierten Add-Methoden erwarten weiß ich nicht - kommt ja auf die Spalten deiner Datatable drauf an.
    Habe mir jetzt ein Mini-Testprogramm erstellt mit nur den zwei Datatables und folgenden Code:

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    3. 'TODO: Diese Codezeile lädt Daten in die Tabelle "EepaDataSet.f_typen". Sie können sie bei Bedarf verschieben oder entfernen.
    4. Me.F_typenTableAdapter.Fill(Me.EepaDataSet.f_typen)
    5. 'TODO: Diese Codezeile lädt Daten in die Tabelle "EepaDataSet.tra_f_typen". Sie können sie bei Bedarf verschieben oder entfernen.
    6. Me.Tra_f_typenTableAdapter.Fill(Me.EepaDataSet.tra_f_typen)
    7. End Sub
    8. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    9. Dim rwNew = EepaDataSet.f_typen.Addf_typenRow(Now, txt_TypeIndex.Text, txt_typeTitle.Text, "")
    10. EepaDataSet.tra_f_typen.Addtra_f_typenRow(Now, rwNew, "en", txt_TraTitle.Text, "")
    11. End Sub
    12. Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
    13. Me.Validate()
    14. F_typenBindingSource.EndEdit()
    15. Tra_f_typenBindingSource.EndEdit()
    16. TableAdapterManager.UpdateAll(EepaDataSet)
    17. End Sub
    18. End Class


    Erhalte jedoch immer noch beim Update die obrige Fehlermeldung.. Vll muss ich nur mal ne Nacht drüber pennen^^
    Diese Fehlermeldung: Zusätzliche Informationen: Die INSERT-Anweisung steht in Konflikt mit der FOREIGN KEY-Einschränkung 'FK_tra_f_typen'. Der Konflikt trat in der eepa-Datenbank, Tabelle 'dbo.f_typen', column 'ftyp_id' auf.

    In Zeile 19 beim TableAdapterManager


    Habe mir eine komplett neue Datenbank mit nur zwei Tables erstellt, dann funktioniert es.. Muss also iwie ein Fehler in der DB sein.. Hier der Code:

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    3. 'TODO: Diese Codezeile lädt Daten in die Tabelle "ShopDataSet.parent". Sie können sie bei Bedarf verschieben oder entfernen.
    4. Me.ParentTableAdapter.Fill(Me.ShopDataSet.parent)
    5. 'TODO: Diese Codezeile lädt Daten in die Tabelle "ShopDataSet.position". Sie können sie bei Bedarf verschieben oder entfernen.
    6. Me.PositionTableAdapter.Fill(Me.ShopDataSet.position)
    7. End Sub
    8. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    9. Dim reNew = ShopDataSet.parent.AddparentRow(TextBox1.Text)
    10. ShopDataSet.position.AddpositionRow(reNew, TextBox2.Text)
    11. End Sub
    12. Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
    13. TableAdapterManager.UpdateAll(ShopDataSet)
    14. End Sub
    15. End Class


    Danke für eure Hilfe:-)


    Fehler auch gleich gefunden: Der Schlüssel war nicht auf Sowohl Beziehungs- als auch Fremdschlüsseleinschränkung, sondern nur auf beziehung. Wurde nicht richtig von der DB übernommen:(
    Egal Problem gelöst

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „T-BoneSteak“ ()

    Kompliment!
    Du hast in kürzester Zeit ein Feeling fürs typisierte Proggen am typDataset entwickelt, und sogar einen fiesen Bug gedebugt, und dabei die Bedeutung der Datarelations geschnackelt.
    Ich empfehle dir aber doch nochmal, die DB erstmal wegzulassen, zumindest bis dein Datenmodell steht.
    ZB mit deine kranken Tabellennamen sind imo inakzeptabel.
    Ausserdem ein echter Modellfehler scheint mir, dass du scheints statt eine Tabelle der Sprachen anzulegen, mit händisch einzugebenden Sprachkürzeln ("en", "de", etc.) rumbastelst.

    Damit bist du gleich an dem Punkt, die DB zu verändern, und das ganze Dataset neu zu generieren, und einiges am Code wird dann auch nicht mehr stimmen, (insbesondere den TableAdapterManager musste runterwerfen und den neuen wieder drauf).

    Also: designe dein Datenmodell im Dataset-Designer.
    Finde kurze, aussagekräftige Tabellennamen - singular, und ohne Prefixe und "_".
    Ebenso die Spaltennamen - du scheinst ja Prefixe zu lieben - lasses - ist nicht nötig.

    gugge nochmal das 4Views-Sample: sowohl Category als auch Article haben eine Spalte "Name". Und das macht nix, denn daraus wird mal die Name-Property der CategoryRow, mal die Name-Property der ArticleRow - also ganz ganz sicher kann da nix durcheinander kommen - kein Prefix erforderlich!

    Und mach Tabellennamen singular. Du wirst viel mehr mit den Rows zu tun haben als mit den Tables.
    Und wenn die Tabelle plural flexiert ist, dann werden es auch die Rows, und das ist semantisch falsch.
    Beispiel: hätte ich die Category-Tabelle "Categories" genannt, so bekäme ich im Code "CategoriesRow" generiert, und das ist falsch, denn eine solche Row repräsentiert nicht mehrere Kategorien, sondern nur eine.