Ich muss ein Wert in einer Tabelle aktualisieren. Dabei habe ich in
meinem Code den Namen der Tabelle, der Spalte und die ID der Zeile. Was
ich nicht habe, ist der Typ der Spalte (boolean, char, date...). Somit
kann ich keinen UPDATE-SQL aufbauen, da man ja abhängig vom Typen
Hochkommas um den Wert braucht (etwa bei Strings). Nun wollte ich für
das Aktualisieren ein Dataset verwenden. Leider komme ich damit nicht
ganz zurecht.
Ich habe Beispiele gefunden, die vor dem Update noch Command-Objekte
aufbauen und dabei wieder den Typen der Spalte angeben (den ich ja nicht
habe). Mache ich sowas nicht, bekomme ich den Fehler "Aktualisieren
erfordert einen gültigen UpdateCommand, wenn eine DataRow-Auflistung mit
modifizierten Zeilen weitergegeben wird."
Laut Doku soll man einen "OleDbCommandBuilder" verwenden. Aber damit
bekomme ich den Fehler "Dynamische SQL-Generierung für den UpdateCommand
wird nicht für einen SelectCommand unterstützt, der keine
Schlüsselspalteninformationen zurückgibt."
Was ich also brauche, ist einen Wert zu ändern und dann einfach .update
aufrufen. Kann man sowas mit einem Dataset machen?
Danke,
Konrad
> Laut Doku soll man einen "OleDbCommandBuilder" verwenden. Aber damit
> bekomme ich den Fehler "Dynamische SQL-Generierung für den UpdateCommand
> wird nicht für einen SelectCommand unterstützt, der keine
> Schlüsselspalteninformationen zurückgibt."
>
> Was ich also brauche, ist einen Wert zu ändern und dann einfach .update
> aufrufen. Kann man sowas mit einem Dataset machen?
Hi Konrad,
ein Update kannst du nicht absenden, wenn du den Datensatz, der zu
aktaulisieren ist, nicht identifizieren kannst. Genau das hat dir der
CommandBuilder mitgeteilt. Es fehlt eine Spalte, die unikate Werte hat, im
allgemeinen ist das eine Schlüsselspalte.
Schreib mal, wie du dir ein Update ohne Schlüsselspalte vorstellst.
--
Viele Gruesse
Peter
> Ich muss ein Wert in einer Tabelle aktualisieren. Dabei
> habe ich in meinem Code den Namen der Tabelle, der
> Spalte und die ID der Zeile. Was ich nicht habe, ist der
> Typ der Spalte (boolean, char, date...).
Den kannst Du aber mit Hilfe der Connection.GetSchema-
Methode ermitteln.
> Somit kann ich keinen UPDATE-SQL aufbauen, da man
> ja abhängig vom Typen Hochkommas um den Wert braucht
> (etwa bei Strings).
Vergiss die Hochkommas in Deinen SQL-Strings und
verwende Parameter-Objekte.
> Nun wollte ich für das Aktualisieren ein Dataset
> verwenden. Leider komme ich damit nicht
> ganz zurecht.
Nachdem Du mit der Connection.GetSchema-Methode
den Datentyp der betr. Spalte ermittelt hast, kannst Du
ein Commandobjekt mit passendem Parameterobjekt
erstellen. Ein DataSet brauchst Du dazu überhaupt nicht.
> Ich habe Beispiele gefunden, die vor dem Update noch
> Command-Objekte aufbauen und dabei wieder den
> Typen der Spalte angeben (den ich ja nicht habe). Mache
> ich sowas nicht, bekomme ich den Fehler "Aktualisieren
> erfordert einen gültigen UpdateCommand, wenn eine
> DataRow-Auflistung mit modifizierten Zeilen
> weitergegeben wird."
>
> Laut Doku soll man einen "OleDbCommandBuilder"
> verwenden.
Nein, Du brauchst nur einen Commandobjekt (UpdateCommand)
mit zugehörigem Parameterobjekt.
> Aber damit bekomme ich den Fehler "Dynamische
> SQL-Generierung für den UpdateCommand
> wird nicht für einen SelectCommand unterstützt, der keine
> Schlüsselspalteninformationen zurückgibt."
>
> Was ich also brauche, ist einen Wert zu ändern und dann
> einfach .update aufrufen. Kann man sowas mit einem
> Dataset machen?
Könnte man, ist aber viel einfacher mit einem simplen
Command-Objekt (SqlCommand, OleDBCommand) und
einem zugehörigen Parameterobjekt zu machen.
Beispiele für die Verwendung von
OleDbConnection.GetSchema()
findest Du unter
www.gssg.de -> Visual Basic -> VB.net
-> OleDB1 (Access.mdb)
für SqlConnection.GetSchema() unter
www.gssg.de -> Visual Basic -> VB.net
-> SQLserver_01
Gruß aus St.Georgen
Peter Götz
www.gssg.de (mit VB-Tipps u. Beispielprogrammen)
Grüße,
Konrad
Danke für den Tipp mit Connection.GetSchema. Ich werde mir das mal
ansehen und wenn ich damit zurecht komme, stampfe ich die Dataset-Idee
wieder ein und verwende wie beschrieben ein Command-Objekt. Von VB6
kommend dachte ich an ein Recordset, was meine Probleme gelöst hätte und
wollte es hier eben ähnlich machen ;-).
Grüße und Danke,
Konrad
Peter Götz schrieb:
> Danke für den Tipp mit Connection.GetSchema. Ich
> werde mir das mal ansehen und wenn ich damit
> zurecht komme, stampfe ich die Dataset-Idee
> wieder ein und verwende wie beschrieben ein
> Command-Objekt. Von VB6 kommend dachte
> ich an ein Recordset, was meine Probleme gelöst
> hätte und wollte es hier eben ähnlich machen ;-).
Mit VB6 und ADODB.Recordset ginge das zwar,
wäre aber auch keine optimale Lösung. Auch hier
wäre ein simpler ADODB.Command völlig ausreichend,
ein Recordset dagegen wäre völlig überflüssiger
Ballast.
> Die habe ich ja. Ich habe die Spalte ID und deren Nummer, sonst könnte ich
> mit dem Select ja den Datensatz auch nicht eindeutig identifizieren. Wie
> ich das allerdings dem CommandBuilder mitteile, weiß ich leider nicht!
Hi Konrad,
das habe ich noch nicht erlebt, dass eine als Primärschlüsselspalte
gekennzeichnete Spalte vom Select nicht erkannt wird, so dass eine
Generierung der Command-Objkete für das Update durch den CommanBuilder nicht
möglich ist.
Teile mal bitte mit:
- welcher OleDb-Provider?
- welcher Datenbank-Datei-Typ?
- wie sieht das Primary Contraint aus?
- nutzt du ein typisiertes DataSet?
- ist im typisiertes DataSetwie die Primärschlüsselspalte unikat?
- ist die Primärschlüsselspalte auch im SELECT enthalten?
- steht vor dem Update noch das richtige SelectCommand im DataAdapter?
- wie sieht das Ergebnis der Get-Methoden des DataAdapters vor dem Update
aus?
--
Viele Gruesse
Peter
Das ist wohl richtig...
Ich habe noch etwas Probleme mit dem DatenTyp-Auslesen. Vielleicht
könntest du mir hierbei noch helfen?
Ich hole mir also folgende Metadaten:
Dim dtSchemaColumns As DataTable = m_oCon.GetSchema("Columns")
Dim dtSchemaDatatypes As DataTable = m_oCon.GetSchema("Datatypes")
Bei dtSchemaColumns finde ich nun meine Tabelle und meine Spalte.
Welchen Eintrag muss aber davon verwenden, um den Datentyp zu bekommen?
Ich habe hier mal den Eintrag unter DATA_TYPE genommen um mit dem
wiederum in dtSchemaDatatypes nach dem eigentlichen Datentyp zu suchen
(Relation über NativeDataType, richtig?). Aber der darin gefundene
ProviderDBType passt nicht als DBType für eine Command-Objekt.
Welchen Eintrag muss ich hier nehmen oder muss ich ihn selber mappen?
Grüße,
Konrad
Peter Fleischer schrieb:
Ich verwende eine Access DB (.mdb mit Provider Microsoft.Jet.OLEDB.4.0).
Ich weiß nicht, ob ich ein typisiertes Dataset verwende. Jedenfalls
ist die Primärschlüsselspalte in dem Select enthalten (select * from
MeineTabelle where ID = xxx). Was ich sonst noch alles tun muss, weiß
ich nicht, da ich das erste mal mit einem Dataset arbeite ;-).
Grüße,
Konrad
>> Teile mal bitte mit:
>>
>> - welcher OleDb-Provider?
>> - welcher Datenbank-Datei-Typ?
>> - wie sieht das Primary Contraint aus?
>> - nutzt du ein typisiertes DataSet?
>> - ist im typisiertes DataSetwie die Primärschlüsselspalte unikat?
>> - ist die Primärschlüsselspalte auch im SELECT enthalten?
>> - steht vor dem Update noch das richtige SelectCommand im DataAdapter?
>> - wie sieht das Ergebnis der Get-Methoden des DataAdapters vor dem Update
>> aus?
>>
>>
>
> Ich verwende eine Access DB (.mdb mit Provider Microsoft.Jet.OLEDB.4.0).
> Ich weiß nicht, ob ich ein typisiertes Dataset verwende. Jedenfalls ist
> die Primärschlüsselspalte in dem Select enthalten (select * from
> MeineTabelle where ID = xxx). Was ich sonst noch alles tun muss, weiß ich
> nicht, da ich das erste mal mit einem Dataset arbeite ;-).
Hi Konrad,
du musst doch wissen, ob du eine xsd aus deinem Projekt als DataSet für das
Fill nutzt.
Da bleiben dann nur die weiteren Fragen:
- wie sieht das Primary Contraint aus? Bzw. wie hast du die
Primärschlüsselspalte angelegt?
- steht vor dem Update noch das richtige SelectCommand im DataAdapter?
- wie sieht das Ergebnis der Get-Methoden des DataAdapters vor dem Update
aus? Z.B. der CommandText?
--
Viele Gruesse
Peter
Peter Fleischer schrieb:
> "Konrad Hammerer" <konrad....@tesis.de> schrieb im Newsbeitrag
> news:11969374...@gzpc.tesis.de...
>
>>> Teile mal bitte mit:
>>>
>>> - welcher OleDb-Provider?
>>> - welcher Datenbank-Datei-Typ?
>>> - wie sieht das Primary Contraint aus?
>>> - nutzt du ein typisiertes DataSet?
>>> - ist im typisiertes DataSetwie die Primärschlüsselspalte unikat?
>>> - ist die Primärschlüsselspalte auch im SELECT enthalten?
>>> - steht vor dem Update noch das richtige SelectCommand im DataAdapter?
>>> - wie sieht das Ergebnis der Get-Methoden des DataAdapters vor dem
>>> Update aus?
>>>
>>>
>>
>> Ich verwende eine Access DB (.mdb mit Provider
>> Microsoft.Jet.OLEDB.4.0). Ich weiß nicht, ob ich ein typisiertes
>> Dataset verwende. Jedenfalls ist die Primärschlüsselspalte in dem
>> Select enthalten (select * from MeineTabelle where ID = xxx). Was ich
>> sonst noch alles tun muss, weiß ich nicht, da ich das erste mal mit
>> einem Dataset arbeite ;-).
>
> Hi Konrad,
> du musst doch wissen, ob du eine xsd aus deinem Projekt als DataSet für
> das Fill nutzt.
Ich habe das Fill folgendermaßen verwendet:
oDataAdapter.Fill(oDataSet, "Auftraege")
>
> Da bleiben dann nur die weiteren Fragen:
>
> - wie sieht das Primary Contraint aus? Bzw. wie hast du die
> Primärschlüsselspalte angelegt?
Als Primary-Key mit Typ Long Integer.
> - steht vor dem Update noch das richtige SelectCommand im DataAdapter?
> - wie sieht das Ergebnis der Get-Methoden des DataAdapters vor dem
> Update aus? Z.B. der CommandText?
Muss ich erst prüfen!
>
>
> Ich habe noch etwas Probleme mit dem DatenTyp-Auslesen.
> Vielleicht könntest du mir hierbei noch helfen?
>
> Ich hole mir also folgende Metadaten:
>
> Dim dtSchemaColumns As DataTable =
> m_oCon.GetSchema("Columns")
> Dim dtSchemaDatatypes As DataTable =
> m_oCon.GetSchema("Datatypes")
Die .GetSchema-Methode lässt sich auch noch weiter
z.B. auf eine ganz bestimmten Tabellennamen
einschränken. Das verringert die Menge der DataRows
welche Du nachher nach Deinen "Column_Name"-Feldern
und "Data_Type"- Feldern durchsuchen musst.
> Bei dtSchemaColumns finde ich nun meine
> Tabelle und meine Spalte.
> Welchen Eintrag muss aber davon verwenden,
> um den Datentyp zu bekommen?
Im Falle von OledbConnection.GetSchema() auf eine
Access.mdb ist es die Spalte DATA_TYPE.
In konkretem Code würde das dann etwa so aussehen:
Dim TblName As String = "tblRCKonstanten"
Dim strBuffer As String = ""
Dim DR As DataRow
Dim DT As DataTable
Dim Restrictions() As String = {Nothing, Nothing, TblName}
DT = mCNN.GetSchema("COLUMNS", Restrictions)
For Each DR In DT.Rows
With DR
If strBuffer.Length > 0 Then
strBuffer &= ControlChars.CrLf
End If
Dim DType As OleDbType = _
CType(.Item("DATA_TYPE"), OleDbType)
strBuffer &= _
.Item("COLUMN_NAME").ToString & _
" : " & DType.ToString & " (" & _
.Item("DATA_TYPE").ToString & ")"
End With
Next
MsgBox(strBuffer, MsgBoxStyle.Information)
> Ich habe hier mal den Eintrag unter DATA_TYPE genommen
Ja, der passt und das ist dann auch schon der gesuchte
Oledb.OledbType den Du bei Deinem Parameter-Objekt
definieren musst.
> um mit dem wiederum in dtSchemaDatatypes nach
> dem eigentlichen Datentyp zu suchen
> (Relation über NativeDataType, richtig?). Aber der
> darin gefundene ProviderDBType passt nicht als
> DBType für eine Command-Objekt.
Nicht für ein Command-Objekt, sondern für ein Parameter-
Objekt und der in der Spalte "DATA_TYPE" gefundene
Wert ist bereits der vom OledbParameter benötigte
Datentyp (OledbType).
>
> Welchen Eintrag muss ich hier nehmen oder muss
> ich ihn selber mappen?
s. Codebeispiel oben.
Damit bekommst Du schon alle notwendigen Informationen.
> Ich habe das Fill folgendermaßen verwendet:
>
> oDataAdapter.Fill(oDataSet, "Auftraege")
Hi Konrad,
und von welchem Typ ist die Variable "oDataSet"? Gib es darin eine DataTable
mit Namen "Auftraege"? Und wenn es diese Tabelle gibt, wie wurde die
Colums-Auflistung geladen bzw. wie sieht da die Spalte für den
Primärschlüssel aus?
>> Da bleiben dann nur die weiteren Fragen:
>>
>> - wie sieht das Primary Contraint aus? Bzw. wie hast du die
>> Primärschlüsselspalte angelegt?
>
> Als Primary-Key mit Typ Long Integer.
Ok, das sieht gut aus - in der der Entwurfsansicht der Tabelle (in Access)
ist also das Schlüsselsysmbol zu sehen.
>> - steht vor dem Update noch das richtige SelectCommand im DataAdapter?
>> - wie sieht das Ergebnis der Get-Methoden des DataAdapters vor dem Update
>> aus? Z.B. der CommandText?
>
> Muss ich erst prüfen!
Dim cb As New OleDbCommandBuilder(myDataAdapter)
Trace.WriteLine(myDataAdapter.SelectCommand.CommandText)
Trace.WriteLine(cb,GetUpdateCommand.CommandText)
--
Viele Gruesse
Peter
Grüße,
Konrad
Peter Götz schrieb:
> Hi Konrad,
> und von welchem Typ ist die Variable "oDataSet"? Gib es darin eine
> DataTable mit Namen "Auftraege"? Und wenn es diese Tabelle gibt, wie
> wurde die Colums-Auflistung geladen bzw. wie sieht da die Spalte für den
> Primärschlüssel aus?
Hier ist mein Test-Code:
Dim strSQL As String = "SELECT " & strSpalte & " FROM " & strTabelle & "
WHERE " & brlvMitgliedHandler.TableIdColumn(strTabelle) & " = " & lngDbId
Dim oDataAdapter As System.Data.OleDb.OleDbDataAdapter = _
New System.Data.OleDb.OleDbDataAdapter(strSQL, m_oCon)
Dim oDataSet As System.Data.DataSet = _
New System.Data.DataSet()
oDataAdapter.Fill(oDataSet)
oDataSet.Tables.Item(0).Rows.Item(0).Item(strSpalte) = strNewValue
Dim oCommandBuilder As New
System.Data.OleDb.OleDbCommandBuilder(oDataAdapter)
oDataAdapter.Update(oDataSet)
>> Als Primary-Key mit Typ Long Integer.
>
> Ok, das sieht gut aus - in der der Entwurfsansicht der Tabelle (in
> Access) ist also das Schlüsselsysmbol zu sehen.
Ja!
>>> - steht vor dem Update noch das richtige SelectCommand im DataAdapter?
>>> - wie sieht das Ergebnis der Get-Methoden des DataAdapters vor dem
>>> Update aus? Z.B. der CommandText?
>
> Dim cb As New OleDbCommandBuilder(myDataAdapter)
> Trace.WriteLine(myDataAdapter.SelectCommand.CommandText)
> Trace.WriteLine(cb,GetUpdateCommand.CommandText)
>
? oDataAdapter.SelectCommand
{System.Data.OleDb.OleDbCommand}
CommandText: "SELECT Fehleinzug FROM 01_01_Main WHERE MNR = 42"
CommandTimeout: 30
CommandType: Text {1}
Connection: {System.Data.OleDb.OleDbConnection}
Container: Nothing
DesignTimeVisible: True
Parameters: {System.Data.OleDb.OleDbParameterCollection}
Site: Nothing
Transaction: Nothing
UpdatedRowSource: Both {3}
? oDataAdapter.UpdateCommand
Nothing
Hi Konrad,
wie sicherst du, dass in der Variablen strSpalte auch immer auch der Name
der Schlüsselspalte enthalten ist? Vermutlich ist dieser Inhalt falsch.
>
> Dim oDataAdapter As System.Data.OleDb.OleDbDataAdapter = _
> New System.Data.OleDb.OleDbDataAdapter(strSQL, m_oCon)
> Dim oDataSet As System.Data.DataSet = _
> New System.Data.DataSet()
Diese Anweisung kann auch einfacher geschrieben werden:
Dim oDataSet As New DataSet
Dazu ist aber auch die Importsanweisung an Anfang des VB-Textes in der Datei
erforderlich, falls nicht projektweit in den Projekteigenschaften gesetzt:
Imports System.Data
>
> oDataAdapter.Fill(oDataSet)
Hier wäre es besser, der implizit neu erzeugten DataTable einen Namen zu
geben.
oDataAdapter.Fill(oDataSet, "Tab1")
oder auch auf das DataSet zu verzichten, da ist für den konkreten Fall (nur
eine Tabelle) keinen Nutzen und nur Ressourcenverbrauch bringt, etwa so:
Dim oDt As New DataTable
oDataAdapter.Fill(oDataTable)
> oDataSet.Tables.Item(0).Rows.Item(0).Item(strSpalte) = strNewValue
> Dim oCommandBuilder As New
> System.Data.OleDb.OleDbCommandBuilder(oDataAdapter)
Hier solltest du noch die Quote-Eigenschaften belegen, damit auch Bezeichner
keine Fehler bringen, die reservierte Schlüsselworte oder Sonderzeichen
enthalten.
With oCommandBuilder
.Quoteprefix = "["
.Qoutesuffix = "]"
End With
> oDataAdapter.Update(oDataSet)
Besser direkt die DataTable angeben:
oDataAdapter.Update(oDataSet,Tables("Tab1"))
oder
oDataAdapter.Update(oDataTable)
>
>>> Als Primary-Key mit Typ Long Integer.
>>
>> Ok, das sieht gut aus - in der der Entwurfsansicht der Tabelle (in
>> Access) ist also das Schlüsselsysmbol zu sehen.
>
> Ja!
Nur nutzt das wenig, wenn die Spalte in der DataTable fehlt.
>
>>>> - steht vor dem Update noch das richtige SelectCommand im DataAdapter?
>>>> - wie sieht das Ergebnis der Get-Methoden des DataAdapters vor dem
>>>> Update aus? Z.B. der CommandText?
>>
>> Dim cb As New OleDbCommandBuilder(myDataAdapter)
>> Trace.WriteLine(myDataAdapter.SelectCommand.CommandText)
>> Trace.WriteLine(cb,GetUpdateCommand.CommandText)
>>
>
> ? oDataAdapter.SelectCommand
> {System.Data.OleDb.OleDbCommand}
> CommandText: "SELECT Fehleinzug FROM 01_01_Main WHERE MNR = 42"
Und Fehleinzug ist wirklich die Schlüsselspalte? Was ist dan MNR? Ich kann
das nicht so richtig glauben.
> CommandTimeout: 30
> CommandType: Text {1}
> Connection: {System.Data.OleDb.OleDbConnection}
> Container: Nothing
> DesignTimeVisible: True
> Parameters: {System.Data.OleDb.OleDbParameterCollection}
> Site: Nothing
> Transaction: Nothing
> UpdatedRowSource: Both {3}
>
> ? oDataAdapter.UpdateCommand
> Nothing
In deinem Code hast du ja auch nichts zugewiesen. Da ist es logisch, dass
Nothing ausgewiesen wird. Der ComandBuilder stellt das Commendobjekt erst
zur Ausführungszeit zur Verfügung, wenn kein Commandobjekt zugewiesen wurde.
Ich vermute mal, dass in der geladenen Tabelle (in deinem Fall "Table1")
keine Schlüsselspalte enthalten ist. Damit kann auch kein Datesatz
aktualisiert werden.
--
Viele Gruesse
Peter
Mein Fehler war, dass ich die ID-Spalte nicht im Select hatte.
Fehleinzug ist die Spalte, die geändert werden soll und MNR ist die ID
Spalte. Ich hatte diese nur in der Where-Bedingung, nicht aber als
Spalte im Select dabei. Ich wusste nicht, dass das nötig ist. Aber es
ist irgendwie logisch ;-)
Danke für die Hilfe,
Konrad
Peter Fleischer schrieb:
> Mein Fehler war, dass ich die ID-Spalte nicht im Select hatte. Fehleinzug
> ist die Spalte, die geändert werden soll und MNR ist die ID Spalte. Ich
> hatte diese nur in der Where-Bedingung, nicht aber als Spalte im Select
> dabei. Ich wusste nicht, dass das nötig ist. Aber es ist irgendwie logisch
> ;-)
Hi Konrad,
vielen Dank für die Rückmeldung. Da hätte ich meine Frage etwas besser
formulieren sollen:-)
- welcher OleDb-Provider?
- welcher Datenbank-Datei-Typ?
- wie sieht das Primary Contraint aus?
- nutzt du ein typisiertes DataSet?
- ist im typisiertes DataSetwie die Primärschlüsselspalte unikat?
- ist die Primärschlüsselspalte auch im SELECT enthalten?
- Ist die Primärschlüsselspalte auch in der DataTable enthalten?
- steht vor dem Update noch das richtige SelectCommand im DataAdapter?
- wie sieht das Ergebnis der Get-Methoden des DataAdapters vor dem Update
aus?
--
Viele Gruesse
Peter
Grüße,
Konrad
Peter Fleischer schrieb: