mysql_insert_id bei typisiertem DataSet?

  • VB.NET
  • .NET 4.5

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

    mysql_insert_id bei typisiertem DataSet?

    Hallo..

    Ich arbeite mit einem typisierten DataSet und mySQL (auf einem Webserver, Multiuser). Es gibt eine Tabelle mit Kundendaten, eine Spalte ist die KundenID (Primärschlüssel Int32 autoincrement). Diese KundenID ist die anwendungsintern "echte" Kundennummer. Für die Darstellung nach außen gibt es eine davon unabhängige sozusagen Alias-Kundennummer.

    Mein Problem ist, daß ich beim Anlegen des Kundendatensatzes die vom Datenbankserver vergebene KundenID nicht kenne. An den Wert würde man mit mysql_insert_id kommen, aber offenbar nicht bei Verwendung von DataSet und DataAdapter.

    Es besteht die Möglichkeit, dass wenn beim Anlegen des Kundendatensatzes zunächst wenig Angaben erfaßt wurden, zufällig ein (soweit) inhaltlich identischer Datensatz existiert. Ich könnte noch eine Spalte mit einem Zeitstempel der letzten Änderung integrieren, dann wäre es weitgehend sicher. Das bleibt aber dennoch eine Hilfskonstruktion.

    Gibt es eine saubere Möglichkeit an den Wert zu kommen?
    --------
    Lieber inkompetent als inkontinent
    Dataset->Db
    Manche DbProvider unterstützen In/Out-Parameter, bei den anderen muss man ein Select hinterherschiessen, um die von der DB vergebene Id zu erfahren.

    Das ist übrigens nicht ein Problem von Dataset und DataAdapter, sondern ein Problem der generierten TableAdapter (ist was anneres als DataAdapter).
    Also die TableAdapter kannste wirklich vergessen. Die erzeugen Megabyte an generiertem Code, und der tut nichtmal was man von ihm erwarten sollte.
    ok, danke!

    Nun laufen mir wieder Deine DB-Extensions über den Weg :)
    Ich hatte mir die schon mal angeguckt, dann aber die Finger davon gelassen, weil mir das anwendungsweite DataSet suspekt war. Wie verhält sich das, wenn in der Anwendung zeitlich an mehreren Stellen an der selben Tabelle 'gearbeitet" wird?

    Konstruiertes Beispiel um zu erklären was ich meine:
    Es gibt es Tabelle Geschäftsvorfälle/Umsätze, die enthalt die selbsterklärenden Spalten: Geschaeftsvorfall_ID, Kunden_ID, NettoBetrag, Datum
    Die Anwendung ermittelt zu jeder vollen Stunde den bisherigen Wochenumsatz und den der Woche zuvor, um einen "Umsatztacho" anzuzeigen, der darstellt, ob der Vertrieb sein Umsatzvolumen hält.
    Quasi im Hintergrund können vollautomatisiert elektronisch eintreffende Aufträge verarbeitet werden.
    Aufträge können aber auch manuell erfaßt bzw. geändert werden.
    Das passiert alles in der selben Anwendung. Was ist, wenn da etwas zeitlich überschneidet?

    Wenn ich es richtig verstehe, werden in die Tabelle im DataSet immer nur die Datensätze aus der Datenbank geladen, die - wenn vorhanden - der WHERE-Bedingung im SQL-SELECT-Command entsprechen. Das sind je nach Anwendungsfall (s.o.) ganz unterschiedliche. Ich lasse mir z.B. die Geschäftsvorfälle des Jahres auflisten, während der "Umsatztacho" aktualisiert wird. Dann sind die Datensätze der Jahresliste weg?
    --------
    Lieber inkompetent als inkontinent

    100Volt schrieb:

    Die Anwendung ermittelt zu jeder vollen Stunde den bisherigen Wochenumsatz und den der Woche zuvor, um einen "Umsatztacho" anzuzeigen, der darstellt, ob der Vertrieb sein Umsatzvolumen hält.
    Quasi im Hintergrund können vollautomatisiert elektronisch eintreffende Aufträge verarbeitet werden.
    Aufträge können aber auch manuell erfaßt bzw. geändert werden.
    Das passiert alles in der selben Anwendung. Was ist, wenn da etwas zeitlich überschneidet?
    Sieh halt zu, dass der eine Vorgang den jeweils anderen blockiert - wenn das nötig ist.
    Dass das nötig ist, sehe ich so noch nicht.
    Ein User kann einen Datensatz zufügen, und iein Timer-gesteuerter Automat kann das auch - dann sinds zwei.

    100Volt schrieb:

    Wenn ich es richtig verstehe, werden in die Tabelle im DataSet immer nur die Datensätze aus der Datenbank geladen, die - wenn vorhanden - der WHERE-Bedingung im SQL-SELECT-Command entsprechen. Das sind je nach Anwendungsfall (s.o.) ganz unterschiedliche. Ich lasse mir z.B. die Geschäftsvorfälle des Jahres auflisten, während der "Umsatztacho" aktualisiert wird. Dann sind die Datensätze der Jahresliste weg?
    Ja, wenn Umsatz-Tacho und Geschäftsvorfälle auf derselben Tabelle rumorgeln.

    Aber die DbPersistance ist ja nicht der Weisheit letzter Schluss. Die kann man sich ja erweitern, wenn man derlei Extra-Anforderungen hat.

    Ich wundere mich übrigens, dass du nu auf die DbExtension eingehst - verlinkt habich doch eine viel schlankere Db-Zugriffs-Klasse.
    Ja, wenn Umsatz-Tacho und Geschäftsvorfälle auf derselben Tabelle rumorgeln.

    Das kommt bei eh nur in verschiedenen Forms/Klassen vor. Dann würde ich einfach je Form/Klasse eine DataSet-Instanz nutzen, und da, wo es drauf an kommt, die Finger von der klassenübergreifenden Verfügbarkeit des DataSet lassen. Ich brauche ja nur die Imports-Anweisung weg lassen.


    Ich wundere mich übrigens, dass du nu auf die DbExtension eingehst - verlinkt habich doch eine viel schlankere Db-Zugriffs-Klasse.

    Der Link zu den DbExtension wurde gleich im zweiten Absatz erwähnt. Ihn nahm zunächst an, daß Dataset->DB darin enthalten sei. Aber ok, ganz unten steht der richtige Link :)

    Ich gucke mir das nachher mal an...
    Danke nochmals!




    Bin nun dabei Dataset->Db auszuprobieren. Wie muß ich den Provider im ConnectionString angeben? PROVIDER=.... ?
    Bislang brauchte ich nichts angeben. Es ist eine mySQL-Datenbank bei all-inkl.com.

    Wenn ich einen oder mehrere Datensätze laden möchte, funktioniert das mit _Persistance.CustomFill, richtig?
    Dann kann ich daran etwas ändern und mit _Persistance.Save werden die Änderungen in die DB geschrieben?
    Zum neu Erstellen eines Datensatzes eine typDataRow erstellen und bei paramValues übergeben?

    ...und so ganz checke ich die Verwendung der "Sicherheits-Fragezeichen" (zur Verhinderung von Sql-Injction-Angriffen) nicht.
    Wo müssen beispielsweise bei diesem KOmmando die Leerzeichen durch Fragezeichen ersetzt werden?
    SELECT * FROM tblNamen WHERE colVorname = 'Klaus' AND colNachname = 'Meyer' AND colJahrgang = 1970;
    Anzugeben ist ja eh nur das hier:
    WHERE colVorname = 'Klaus' AND colNachname = 'Meyer' AND colJahrgang = 1970;

    Ich würde gerne damit was machen, aber mir fehlt der Einstieg. Was nützt das genialste Werkzeug, wenn man damit nicht umzugehen weiß ;)
    Ein paar grundlegende Beispiele wären toll.

    Beiträge zusammengefasst ~VaporiZed
    --------
    Lieber inkompetent als inkontinent

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

    100Volt schrieb:

    Aber ok, ganz unten steht der richtige Link
    Ich hoffe, du meinst den Download-Link, und nicht noch irgendwas anderes.

    100Volt schrieb:

    Ein paar grundlegende Beispiele wären toll.
    Der Download-Link enthält eine Beispiel-Solution mit grundlegenden Beispielen.

    Zur Frage mit den Fragezeichen:

    VB.NET-Quellcode

    1. ...
    Nee - ich kau dir das jetzt nicht vor.
    Öffne die Beispiel-Solution, mache eine Text-Search nach 'CustomFill' - da findest du Beispiele, ich glaub sogar viele.

    Einige wirst du verstehen, andere vielleicht nicht.
    Darüber kann man reden.
    Bzgl. der Angabe des Providers im ConnectionString komme ich nicht weiter.

    Bislang sieht der bei mir so aus:
    "SERVER=" & My.Settings.DB_Server & ";DATABASE=" & My.Settings.DB_Name & ";UID=" & My.Settings.DB_Benutzer & ";PASSWORD=" & My.Settings.DB_Passwort & ";"

    Vermutlich muß der erweitert werden um:
    PROVIDER=x;

    Aber was ist x?
    --------
    Lieber inkompetent als inkontinent
    Also ich habe mir eine MySQL Klasse geschrieben, welche alle wichtigen MySQL Befehle (SELECT, UPDATE, INSERT und DELETE) abarbeitet.

    Bei INSERT lese ich die ID des neuen Datensatzes aus und übergeben ihn als RETURN Wert. Anbei ein Auszug davon...

    VB.NET-Quellcode

    1. Public Function InsertData(ByVal Sql As String, Optional ShowError As Boolean = False) As Long
    2. Try
    3. Dim affectRows As Long
    4. _error = ""
    5. If conn Is Nothing Then
    6. conn = New MySqlConnection(ConnString)
    7. End If
    8. conn.Open()
    9. Using cmd As MySqlCommand = New MySqlCommand(Sql, conn) With {.CommandTimeout = 60}
    10. affectRows = cmd.ExecuteNonQuery()
    11. affectRows = cmd.LastInsertedId
    12. End Using
    13. conn.Close()
    14. Return affectRows

    Der ConnectionString muss so aussehen.

    "Server=[Servername oder IP]; Port=[Port]; UID=[Benutzername]; password=[Passwort]; Initial Catalog=[Datenbank]"

    Server: IP-Adresse oder Servername
    Port: Standard 3306 oder auf welchem der MySQL reagiert
    UID: Benutzername, welcher Zugriffsrechte auf die Datenbank und den Tabellen hat
    Password: selbsterklärend
    Intitial Catalog: Datenbank

    Es gibt dann noch weitere Parameter, aber diese muss der Connection String beinhalten.

    # EDIT #
    Bei Provider müsstest MySql.Data.MySqlClient schreiben, aber eigentlich im Connectionstring nicht notwendig.
    Es kommt an der markierten Stelle (Dataset->Db, MiscX.vb):

    VB.NET-Quellcode

    1. Public Module DataCommonX
    2. 'weiterer Code........
    3. Private Class DoorKeeper : Implements IDisposable ' Wenn er die Connection öffnen musste, dann schliesst er sie auch wieder
    4. Private _Con As IDbConnection
    5. Public Sub New(Con As IDbConnection)
    6. If Con.State = ConnectionState.Closed Then _Con = Con : [color=#FF0000][b]_Con.Open()[/b][/color]
    7. End Sub
    8. Public Sub Dispose() Implements IDisposable.Dispose
    9. If _Con IsNot Nothing Then _Con.Close() : _Con = Nothing
    10. End Sub
    11. End Class
    12. End Module


    zu diesem Fehler:
    System.InvalidOperationException: "Der 'MySQLProv'-Provider ist nicht auf dem lokalen Computer registriert."

    Der ConnectionString muß laut der empfohlenen Webseite so aussehen:
    Provider=MySQLProv;Data Source=mydb;User Id=myUsername;Password=myPassword;

    Vielleicht muß statt den Zeichen MySQLProv etwas anderes dort stehen, aber wenn ja, was?
    Mein Projekt hat einen Verweis auf die MySql.Data.dll, vielleicht braucht das Dataset->Db-Projekt bzw. die darus kompilierte .dll den auch? ..oder ich kann das im Nachinein irgendwie zuweisen?

    Der Fehler macht den Eindruck, als wisse die erzeugte OleDbPersistance-Instanz nicht, daß sie es mit mySQL zu tun hat.
    --------
    Lieber inkompetent als inkontinent

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

    mir macht das den Eindruck, als sei mySql nicht richtig installiert, oder der Connectionstring ist falsch - jedenfalls funktioniert er nicht.

    Kann auch sein, dass MySql nicht mit OleDb zusammenarbeitet. Da müsste man einen MySqlPersistance coden - also per Text-Ersatz sämtliche Vorkommen von 'OleDb' ersetzen durch 'MySql'.

    Aber du hast überprüft, dass du mit herkömmlichen Mitteln Daten abrufen kannst von deine WebServer-MySql-DB?

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

    Also ich verwende seit gefühlten 10 Jahren diese Schreibweise "Server=[Servername oder IP]; Port=[Port]; UID=[Benutzername]; password=[Passwort]; Initial Catalog=[Datenbank]" und es funktioniert sogar mit MySQL Version 8.x noch immer.
    Hast es schon versucht?
    Warum versucht du nicht einmal Provider = MySql.Data.MySqlClient

    # EDIT #
    Siehe einmal hier: https://dev.mysql.com/doc/connector-net/en/connector-net-connections-string.html

    # EDIT 2 #
    https://dev.mysql.com/doc/dev/connector-net/8.0/html/P_MySql_Data_MySqlClient_MySqlConnection_ConnectionString.htm

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

    mir macht das den Eindruck, als sei mySql nicht richtig installiert...

    Einen lokalen mySQL-Server habe ich nicht. Die Datenbank liegt bei all-inkl.com.


    Es sind vier Projekte in der Projektmappe von Dataset->Db:
    1. AccessSample (Beispiel mit Forms)
    2. DbPersistanceCs (irgendeine Klasse in C#)
    3. MiniHelpers (s.u.)
    4. SqlCeSample (Beispiel mit Forms)

    In 3. (MiniHelpers) gibt es:
    3a. DbPersistanceBase.vb (nur vererbbar)
    3b. MiscX.vb (wohl Hilfsfunktionen)
    3c. OleDbPersistance.vb
    3d. SqlServerPersistance.vb

    Es sieht nicht so aus, als gäbe es speziell für mySQL etwas. Ich versuche dann die Modifikation von OleDbPersistance.vb

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

    @GerhardW:
    Mein ConnectionString sieht im Grunde so aus wie Deiner, bis auf den Port, den ich nicht explizit angebe.
    Die Idee mit Provider=MySql.Data.MySqlClient geht leider auch nicht.

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

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

    versuche mal die beiden

    VB.NET-Quellcode

    1. Public MySqlCon1 As String = "Persist Security Info=False;Server=[Servername oder IP]; Port=[Port]; UID=[Benutzername]; password=[Passwort]; Initial Catalog=[Datenbank]"
    2. Public MySqlCon2 As String = "Persist Security Info=False;datasource=all-inkl.com; Port=[Port]; UID=[Benutzername]; password=[Passwort]; Initial Catalog=[Datenbank]"
    Das Dataset->Db-Projekt gibt es hier:
    Dataset->Db

    Bei mir steht das testweise in einer Klasse:

    VB.NET-Quellcode

    1. Private _Con As MySql.Data.MySqlClient.MySqlConnection
    2. Private _Adapters As Dictionary(Of DataTable, MySql.Data.MySqlClient.MySqlDataAdapter)
    3. Private _RankedTables As List(Of DataTable)
    4. Private _Dts As DataSet
    5. Private _RequeryIdCommand As MySql.Data.MySqlClient.MySqlCommand ' not neccessary, if in-/out-DbParameter-Support is present
    6. Private cOleDbPersistance As OleDbPersistance
    7. Public Sub New()
    8. InitializeComponent()' Dieser Aufruf ist für den Designer erforderlich.
    9. cOleDbPersistance = New OleDbPersistance(modZentraleAufgaben.GetConnectionStringProvider, DsMain)
    10. cOleDbPersistance.CustomFill(DsMain.tblKunden, "where " & DsMain.tblKunden.VornameColumn.ColumnName & " = " & txtVorname.text)
    11. End Sub


    Der Fehler tritt bei der Zeile
    cOleDbPersistance.CustomFill(DsMain.tblKunden, "where " & DsMain.tblKunden.VornameColumn.ColumnName & " = " & txtVorname.text)
    auf
    --------
    Lieber inkompetent als inkontinent

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