mysql_insert_id bei typisiertem DataSet?

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

Es gibt 81 Antworten in diesem Thema. Der letzte Beitrag () ist von 100Volt.

    Was mir aufgefallen ist:
    ... cOleDbPersistance.CustomFill(DsMain.tblKunden, "where " & DsMain.tblKunden.VornameColumn.ColumnName & " = " & txtVorname.text)

    müsste das nicht so sein:

    ... cOleDbPersistance.CustomFill(DsMain.tblKunden, "where " & DsMain.tblKunden.VornameColumn.ColumnName & " = "'" & txtVorname.text + "'")

    also txtVorname.Text muss doch, weil wahrscheinlich ein Varchar Feld in MySQL, mit ' begrenzt sein...

    es sollte wie folgt inhaltlich sein: where [Tabellenfeld] = 'Gerhard'

    Die Klasse OleDbPersistance ist Bestandteil des Helpers-Projektes in Dataset->Db, das ErfinderDesRades mal geschrieben hat, um das es seit Post #2 in diesem Thread geht :)

    Die Idee von Post #12:
    ...MySqlPersistance coden - also per Text-Ersatz sämtliche Vorkommen von 'OleDb' ersetzen durch 'MySql'.

    hat nicht funktioniert. Vielleicht stelle ich mich auch einfach zu doof an.
    Falls jemand das selbst versuchen möchte, und es ihm lediglich an einer mySQL-Datenbank mangelt, die könnte ich auf dem Server zur Verfügung stellen. Habe 100 frei und nutze aktuell eine.


    --------------

    @GerhardW, Post #21:
    Das soll die EB-Extensions - sofern mit einem typisierten DataSet gefüttert - selbst machen, wenn ich es richtig verstanden habe. Das soll ja gerade einer der Vorteile sein, daß man sich um sowas nicht mehr kümmern muß.
    Die Fehlermeldung klingt aber auch nicht nach fehlendem Hochkomma, finde ich.

    --------
    Lieber inkompetent als inkontinent
    Klar, ich arbeitete schon seit Wochen problemlos mit der Datanbank. Das schrieb ich auch bereits.


    Ich habe mir auf die Schnelle (Ursprungsproblem, Post #1) nun erstmal hiermit beholfen:

    VB.NET-Quellcode

    1. Friend Function SQL_ID_Erstellen(ByVal tbl As DataTable, ByVal col As DataColumn) As Long
    2. Try
    3. Dim myConn As New MySql.Data.MySqlClient.MySqlConnection(modZentraleAufgaben.GetConnectionString)
    4. Dim myCommand As New MySql.Data.MySqlClient.MySqlCommand
    5. myCommand.Connection = myConn
    6. myConn.Open()
    7. myCommand.CommandText = "INSERT INTO " & tbl.TableName & " (" & col.ColumnName & ") VALUES (0)"
    8. myCommand.ExecuteNonQuery()
    9. Return myCommand.LastInsertedId
    10. Catch ex As Exception
    11. Return 0 - Math.Abs(ex.HResult)
    12. End Try
    13. End Function


    Aufruf:
    SQL_ID_Erstellen(dsMain.tblKunden, dsMain.tblKunden.ID_KundeColumn)

    Meine Primärschlüsselspalten starten immer bei 1 und erhöhen sich um 1. DBNull ist ansonsten in jeder Spalte erlaubt. Unter diesen Voraussetzungen funktioniert dieser Code.
    Ich "reserviere" mir damit sozusagen eine ID, die ich kenne. Sobald ich diese habe, arbeite ich mit bequemeren Mittel, als mySQL-zu-Fuß weiter ;)
    --------
    Lieber inkompetent als inkontinent
    gefällt mir so noch nicht die Lösung. Ich schau' die Tage mal, ob ich mein Riesenkonstrukt an Tabellen in eine mySQL-Datenbank importiert bekomme und teste daran dann die DBExtensions bzw. das DataSet-DB, welches ich aktuell erfolgreich für
    OleDB (Access-Datenbank) benutze. Kann ja nicht schaden, eine lauffähige mysql-Variante davon zu besitzen :P
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:
    So, die Tabellen kann ich nun sauber erstellen in der Datenbank.
    Hat jemand ein ordentliches nuget-paket (mysql), was auch mit .NET 4.0 läuft? Ich finde irgendwie nur welche die 4.6 oder sowas benötigen. Mein Projekt läuft allerdings auf 4.0...
    vorher brauch' ich da nix umbauen

    EDIT: hab ein älteres nuget-paket genommen. Bei mir klappt gerade das Füllen der DB mit Daten nicht (nutze MariaDB), kann aber an meiner Struktur liegen, das muss alles noch
    bereinigt werden. Könntest aber mal probieren:

    VB.NET-Quellcode

    1. Imports MySql.Data.MySqlClient
    2. Imports System.Data.Common
    3. Public Class MySqlServerPersistance : Inherits DbPersistanceBase
    4. Private _Connection As MySqlConnection
    5. Public Sub New(connectionString As String, dts As DataSet)
    6. MyBase.New(dts)
    7. #If False Then
    8. "MultipleActiveResultSets=true;" im ConnectionString sicherstellen
    9. Das ermöglicht, eine ChildTable mit Children der ersten eingetroffenen ParentRow zu befüllen, auch wenn die ParentTable-Befüllung noch garnet abgeschlossen ist
    10. Nützich bei Parent->Child->Child - Views
    11. #End If
    12. Dim builder = New MySqlConnectionStringBuilder(connectionString) ' With {.MultipleActiveResultSets = True}
    13. _Connection = New MySqlConnection(builder.ConnectionString)
    14. End Sub
    15. Private Shared Sub TryInitAutoIncrement(tb As DataTable, insertCommand As MySqlCommand)
    16. 'Bei AutoIncrement-Primkeys wird dem Insert-CommandText ein Select-Command angehängt, welches den Db-seitig generierten Pk rücktransportiert
    17. Dim pk = tb.PrimaryKey
    18. If pk.Length <> 1 OrElse Not pk(0).AutoIncrement Then Return
    19. insertCommand.CommandText &= String.Format("; SELECT [{0}] FROM [{1}] WHERE [{0}] = SCOPE_IDENTITY()", pk(0).ColumnName, tb.TableName)
    20. insertCommand.UpdatedRowSource = UpdateRowSource.Both
    21. End Sub
    22. Protected Overrides Function CreateAdapter(table As DataTable) As DbDataAdapter
    23. Dim adp = New MySqlDataAdapter(String.Format("Select `{0}`.* from `{0}`", table.TableName), _Connection)
    24. Using builder = New MySqlCommandBuilder(adp) With {.ConflictOption = ConflictOption.OverwriteChanges}
    25. With adp
    26. .UpdateCommand = builder.GetUpdateCommand.Clone
    27. .InsertCommand = builder.GetInsertCommand.Clone
    28. TryInitAutoIncrement(table, .InsertCommand)
    29. .DeleteCommand = builder.GetDeleteCommand.Clone
    30. .TableMappings.Add(DbDataAdapter.DefaultSourceTableName, table.TableName)
    31. End With
    32. End Using
    33. Return adp
    34. End Function
    35. End Class


    Initialisiert wird das bei mir wie folgt:

    VB.NET-Quellcode

    1. Partial Class DATASET-NAME
    2. Public Shared ReadOnly Dts As DATASET-NAME
    3. Public _Persistance As MySqlServerPersistance
    4. Private _sCon As String = Nothing
    5. Shared Sub New()
    6. Dts = New DATASET-NAME
    7. Dts.Persist(False, Dts.Tables.Cast(Of DataTable).Where(Function(tb) tb.PrimaryKey.Length = 0).ToArray) 'Tabellen ohne PrimKey-Column aus Persistierung rausnehmen
    8. Dts._sCon = "Server=SERVER-IP; UID=USERNAME; password=PASSWORD; Initial Catalog=DB-NAME"
    9. Dts._Persistance = New MySqlServerPersistance(Dts._sCon, Dts)
    10. End Sub


    Also er will Daten füllen, schafft es auch zu einem gewissen grad, dann meckert er wegen constraints. Das kann aber wie gesagt an meinem Konstrukt liegen. Naja, teste halt einfach mal
    und gib' mir Rückmeldung.

    EDIT2:

    ggf. muss da auch was anneres hin als SCOPE_IDENTITY()
    folgende Fehler tauchen bei mir auf:

    Quellcode

    1. FEHLER!: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '[ID] FROM [Ansicht] WHERE [ID] = SCOPE_IDENTITY()' at line 1Tree
    2. FEHLER!: Cannot add or update a child row: a foreign key constraint fails (`test`.`Tree`, CONSTRAINT `FK_Ansicht_Tree0` FOREIGN KEY (`tlView`) REFERENCES `Ansicht` (`Typ`) ON UPDATE CASCADE)MitarbeiterFunktion
    3. FEHLER!: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '[ID] FROM [MitarbeiterFunktion] WHERE [ID] = SCOPE_IDENTITY()' at line 1Gesellschaft
    4. FEHLER!: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '[ID] FROM [Gesellschaft] WHERE [ID] = SCOPE_IDENTITY()' at line 1StandortTyp
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:

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

    tragl schrieb:

    ggf. muss da auch was anneres hin als SCOPE_IDENTITY()
    Jo, das steht glaub in post#1 - bei mySql heisstes wohl mysql_insert_id - wie es bei Maria heisst, steht wohl bei Maria.

    Aber das fände ich ja toll, wenn das ans laufen gebracht wird. Da tät ich dich bitten, das dem Persistance-Tut anzuhängen, dass somit ein weiterer DbProvider unterstützt wird.
    Aber erstmal laufen sehen.

    (Äh - wie jetzt - du hast dein ganzes Logistik-Tool-Monstrum gschwind mal nach Maria migriert? - du meine Güte! - Hut ab!)

    ErfinderDesRades schrieb:

    bei mySql heisstes wohl


    genau genommen heißt es LAST_INSERT_ID()
    Ich hab deinen DB-Generator ein bisschen umgebaut, sodass auch die ; am Ende erscheinen, wenn man MySQL benutzt, ansonsten muss man jeden SQL-Befehl einzeln ausführen.

    Ansonsten: Ja, meine 71 Tabellen sind in der MariaDB (MySql) drin - inkl. Constraints :D
    Das Schreiben der Daten klappt auch bis auf 1-2 Felder, wo ich den VarChar-Wert über 255 stellen muss weil ich da ziemlich langen Text drin hab.


    Wenn die Daten komplett und fehlerfrei hochgeladen sind, teste ich das laden und Rückspeichern aus. Wenn das funzt, wie es soll dann kann ich gerne was für's Persistance-Tut fertig machen.
    Ich melde mich aber hier an der Stelle auch nochmal wenn's geklappt hat. Sieht bisher ganz gut aus ;)
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:
    Sooo....
    @100Volt: Bitte mal testen - dann kannste dir das manuelle geklapper sparen.

    Ich hab nu ma bisschen getestet und gebastelt. Bei mir läuft das einwandfrei auf einem MariaDB-Server (ist quasi das Gleiche wie MySQL)
    Als NuGet-Paket hab ich folgendes genommen (alt, weil ich Framework 4.0 benutze):

    Vorsicht: Ihr müsst auf das Lizenzmodell acht geben. Ich hab mir das jetzt nicht genau angeguckt - sollte prinzipiell aber mit jedem anderen MySQL-NuGet-Paket funzen.

    Dann folgende Klasse zur DbPersistance hinzufügen: ich hab sie bei mir MySqlServerPersistance.vb genannt

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Imports MySql.Data.MySqlClient
    2. Imports System.Data.Common
    3. Public Class MySqlServerPersistance : Inherits DbPersistanceBase
    4. Private _Connection As MySqlConnection
    5. Public Sub New(connectionString As String, dts As DataSet)
    6. MyBase.New(dts)
    7. Dim builder = New MySqlConnectionStringBuilder(connectionString) 'With {.MultipleActiveResultSets = True} 'TRAGL: wird von MySQL nicht unterstützt
    8. _Connection = New MySqlConnection(builder.ConnectionString)
    9. End Sub
    10. Private Shared Sub TryInitAutoIncrement(tb As DataTable, insertCommand As MySqlCommand)
    11. 'Bei AutoIncrement-Primkeys wird dem Insert-CommandText ein Select-Command angehängt, welches den Db-seitig generierten Pk rücktransportiert
    12. Dim pk = tb.PrimaryKey
    13. If pk.Length <> 1 OrElse Not pk(0).AutoIncrement Then Return
    14. insertCommand.CommandText &= String.Format("; SELECT `{0}` FROM `{1}` WHERE `{0}` = LAST_INSERT_ID()", pk(0).ColumnName, tb.TableName)
    15. insertCommand.UpdatedRowSource = UpdateRowSource.Both
    16. End Sub
    17. Protected Overrides Function CreateAdapter(table As DataTable) As DbDataAdapter
    18. Dim adp = New MySqlDataAdapter(String.Format("Select `{0}`.* from `{0}`", table.TableName), _Connection)
    19. Using builder = New MySqlCommandBuilder(adp) With {.ConflictOption = ConflictOption.OverwriteChanges}
    20. With adp
    21. .UpdateCommand = builder.GetUpdateCommand.Clone
    22. .InsertCommand = builder.GetInsertCommand.Clone
    23. TryInitAutoIncrement(table, .InsertCommand)
    24. .DeleteCommand = builder.GetDeleteCommand.Clone
    25. .TableMappings.Add(DbDataAdapter.DefaultSourceTableName, table.TableName)
    26. End With
    27. End Using
    28. Return adp
    29. End Function
    30. End Class


    In der Businesslogik vom DataSet nutze ich folgendes dafür:

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Partial Class dtsLogistik
    2. Public Shared ReadOnly Dts As dtsLogistik
    3. Public _Persistance As MySqlServerPersistance
    4. Private _sCon As String = Nothing
    5. Shared Sub New()
    6. Dts = New dtsLogistik
    7. Dts.Persist(False, Dts.Tables.Cast(Of DataTable).Where(Function(tb) tb.PrimaryKey.Length = 0).ToArray) 'Tabellen ohne PrimKey-Column aus Persistierung rausnehmen
    8. Dts._sCon = "Server=192.168.178.6; UID=ltool; password=test; Initial Catalog=ltool;"
    9. Dts._Persistance = New MySqlServerPersistance(Dts._sCon, Dts)
    10. Try
    11. Dts._Persistance.Connection_EnterOpen()
    12. msgInformation("MySQL Verbindung OK")
    13. Catch ex As Exception
    14. msgEx(ex)
    15. End Try
    16. End Sub
    17. End Class


    Jo. Damit kann ich alles Mögliche an Unfug anstellen, wie mit meiner Access-Datenbank auch. Laden, speichern, löschen etc.
    Viel Spaß damit.

    @ErfinderDesRades: Wenn du magst, dann häng das gerne an's Tut mit dran für MySQL und MariaDB
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:
    Das ging ja fix! :) Vielen Dank!

    Nach diesem Aufruf:
    cMySqlServerPersistance.CustomFill(DsMain.tblKunden, "where " & DsMain.tblKunden.VornameColumn.ColumnName & " = " & txtVorname.text)

    kommt es hier:
    Public Sub CustomFill(table As DataTable, preamble As String, sqlAfterFrom As String, args As Object()) .....

    zu einer Fehlermeldung, die offenbar an diesem Command liegt:
    Select `tblKunden`.* from `tblKunden` where Vorname =

    Der Server wird das Sternchen doof finden, denke ich ;)
    --------
    Lieber inkompetent als inkontinent

    100Volt schrieb:

    Das ging ja fix!


    Ich hab eigentlich nur das gemacht, was ErfinderDesRades ein paar Posts weiter vorne gesagt hat: Die SqlServerPersistance ausgetauscht dur MySql...
    Zu deinem Command:

    Wenn deine Datenbank relativ klein ist würde ich die erstmal über
    DsMain._Persistance.FillAll() komplett reinladen.
    Wenn du Teilstücke brauchst, dann so:
    DsMain.tblKunden.CustomFill("WHERE Vorname = ?", txtVorname.text
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:
    @tragl:
    Stimmt, da war ja die Sache mit den Fragezeichen :) Danke, das war´s!

    @petaod:
    Daran lag es so nicht. Ich habe es nicht vergessen, nur falsch übergeben. So ist der Aufruf (aus meinem Code) richtig:
    cMySqlServerPersistance.CustomFill(dsMain.tblKunden, "where " & dsMain.tblKunden.VornameColumn.ColumnName & " = ?", txtVorname.txt)
    --------
    Lieber inkompetent als inkontinent

    100Volt schrieb:

    So ist der Aufruf (aus meinem Code) richtig:


    haste mal hiermit DsMain.tblKunden.CustomFill("WHERE Vorname = ?", txtVorname.text probiert? oder garnicht erst getestet?
    Außerdem kennst du String-Interpolation? $"WHERE {dsMain.tblKunden.VornameColumn.Columname} = ?", txtVorname.txt

    Nichts desto trotz bin ich der Meinung, dass mein Vorschlag oben auch funzt und das wirkt einiges sauberer.
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:
    Sorry, ich habe jetzt erst gesehen was Du meinst. Das hatte ich nicht probiert, da mir gar nicht klar war, daß das so (DsMain.tblKunden.CustomFill...) auch gehen würde.


    ---------Nachtrag---------

    Ich wollte DsMain.tblKunden.CustomFill... gerade ausprobieren.

    .CustomFill ist kein Member von [tt]DsMain.tblKunden/tt]

    Was mache ich denn nun schon wieder falsch?

    So schaut es aus:

    VB.NET-Quellcode

    1. Private cMySqlServerPersistance As MySqlServerPersistance
    2. Private Sub test()
    3. cMySqlServerPersistance = New MySqlServerPersistance(GetConnectionString, DsMain)
    4. 'DsMain.tblKunden.CustomFill...
    5. End Sub

    --------
    Lieber inkompetent als inkontinent

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

    100Volt schrieb:

    Was mache ich denn nun schon wieder falsch?

    kommt drauf an. Der Customfill funktioniert bei mir so

    DataSetName.Tabellenname.CustomFill($"WHERE {SpaltenName} = ?",Bedingung)

    Bei mir ist das DataSet aber über die Businesslogik gekennzeichnet (siehe bei meinem Lösungspost von mysql) - wenn du das bei dir genauso handhabst
    Dann sollte das bei dir auch genauso funzen

    Also:

    VB.NET-Quellcode

    1. Partial Class DataSetName
    2. Public Shared ReadOnly Dts As DataSetName
    3. Public _Persistance As MySqlServerPersistance
    4. Private _sCon As String = Nothing
    5. Shared Sub New()
    6. Dts = New DataSetName
    7. Dts.Persist(False, Dts.Tables.Cast(Of DataTable).Where(Function(tb) tb.PrimaryKey.Length = 0).ToArray) 'Tabellen ohne PrimKey-Column aus Persistierung rausnehmen
    8. Dts._sCon = "Server=SERVER-IP/SERVER-FQDN; UID=DB-USER; password=DB-PASSWORD; Initial Catalog=DATABASE-NAME;"
    9. Dts._Persistance = New MySqlServerPersistance(Dts._sCon, Dts)
    10. Try
    11. Dts._Persistance.Connection_EnterOpen()
    12. msgInformation("MySQL Verbindung OK")
    13. Catch ex As Exception
    14. msgEx(ex)
    15. End Try
    16. End Sub
    17. End Class


    Dann hast du auch von überall in deiner anwendung mit Dts.xxx zugriff auf dein DataSet und mit z.B.Dts.TabellenName.CustomFill(...) kannst von überall deine Tabellen befüllen
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:
    Wohin genau muß der Code, der in Post #30 in der Klasse dtsLogistik bzw. in Post #37 in der Klasse DataSetName steht?
    Der Begriff Businesslogik ist für mich nicht so richtig greifbar. Via Google konnte ich auch keine Erleuchtung herbeiführen.

    Das beißt sich dann wahrscheinlich mit Me.DsMain.Register(Me, True) (stammt aus dem Helpers-Projekt von EdR.
    --------
    Lieber inkompetent als inkontinent
    Mit Starthilfe (@Tragl: Herzlichen Dank!) läuft das DataSet->DB/Helpers-Projekt bei mir nun :)

    An einigen Stellen in meiner Anwendung müssen Datensätze im Code geladen und aktualisiert bzw. neu erstellt werden.

    Das Suchen eines Kunden mit Namen geschieht so:

    VB.NET-Quellcode

    1. Dts.tblKunden.Clear()
    2. Dts.tblKunden.CustomFill($"{Dts.tblKunden.VornameColumn.ColumnName}=?AND {Dts.tblKunden.VornameColumn.ColumnName}=?AND {Dts.tblKunden.GeburtsdatumColumn.ColumnName}=?",
    3. {strVorname, strNachname, datGeburtsDatum})
    4. Return Dts.tblKunden.Count


    Das Suchen eines Kunden mit seiner Kunden-ID:

    VB.NET-Quellcode

    1. Dts.tblKunden.Clear()
    2. Dts.tblKunden.CustomFill($"{Dts.tblKunden.ID_KundeColumn.ColumnName}=?",
    3. {intKundennummerAktuell})
    4. Return Dts.tblKunden.Count


    Wobei dieses hier einfacher zum selben Ergebnis führen dürfte:

    VB.NET-Quellcode

    1. Dts.tblKunden.Clear()
    2. Dts.tblKunden.FindByID_Kunde(intKundennummerAktuell)
    3. Return Dts.tblKunden.Count


    Dann beginnen die Unklarheiten.
    Sofern die Abfrage zu genau einem Treffer führte, müßte ich so an die Kundendaten kommen:

    VB.NET-Quellcode

    1. strVorname = Dts.tblKunden.Rows(0).Item(Dts.tblKunden.VornameColumn)
    2. strNachname = Dts.tblKunden.Rows(0).Item(Dts.tblKunden.NachnameColumn)

    Ist das so der vorgesehene Weg? Oder soll das über Dim row = Dts.tblKunden.LoadDataRow() geschehen? Wobei mir hier unklar ist, wie die Values auszusehen haben.


    Das Verändern eines geladenen Datensatz so?

    VB.NET-Quellcode

    1. Dts.tblKunden.Rows(0).Item(Dts.tblKunden.VornameColumn) = strVorname
    2. Dts.tblKunden.Rows(0).Item(Dts.tblKunden.NachnameColumn) = strNachname



    Und das Erstellen eines neuen Datensatz so?

    VB.NET-Quellcode

    1. Dim row = Dts.tblKunden.NewtblKundenRow()
    2. row.Vorname = strVorname
    3. row.Nachname = strNachname
    4. Dts.tblKunden.AddtblKundenRow(row)


    Wie komme ich an die Last_Inserted_Id, den Int32 autoincrement Primärschlussel der tblKunden, den ich als Kunden-ID verwenden möchte? Der Datensatz wird erst mit Dts.Save in die Datenbank geschrieben, oder? Dann kann ich den Wert auch erst danach auslesen.
    So ganz rund ist diese manuelle Schiene für mich noch nicht...

    --------
    Lieber inkompetent als inkontinent

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