none
[ACCESS 03] Schreiboperation (Update, Insert, Delete) auf ein Query (bzw. View) mittels OleDbDataAdapter

    Frage

  • Hallo Freunde,

    ich habe zwei Quelltabellen, die in einem Access-Query (...die Access Bezeichnung für View) joine. Auf dieses Query greife ich in meiner C#.NET-Applikation mittels OleDbDataAdapter zu und fülle mein DataSet. Nun möchte ich Zeilen verändern, hinzufügen und löschen.

    PROBLEM:

    Die OleDbCommandBuilder ist lt. Exception zu blöd, bei mehreren Quelltabellen, entsprechende SQL-Statements zu generieren.

    Ein erster "händischer" Versuch, Daten per OleDbCommand("INSERT INTO myQuery VALUES (1, 2, 3)", myCon); in die Query (hab die Query wie eine normale Tabelle adressiert) hineinzuschreiben gelingt.

    FRAGE:

    Wie aber geht es mit einem OleDbDataAdapter? Notfalls müsste ich zeilenweise Updaten und mit Parametern arbeiten, wobei mir kein Weg bekannt ist, die SQL-Statements des DataAdapters direkt zu manipulieren.

    MfG

    Flux1989

    Dienstag, 14. August 2012 16:26

Alle Antworten

  • Flux1989 wrote:

    Wie aber geht es mit einem OleDbDataAdapter? Notfalls müsste ich
    zeilenweise Updaten und mit Parametern arbeiten, wobei mir kein Weg
    bekannt ist, die SQL-Statements des DataAdapters direkt zu manipulieren.

    Wieso öffnest Du nicht einfach eine Connection und dort ein SqlCommand? Dort kannst Du dann den CommandText beliebig setzen und dann ein ExecuteNonQuery ausführen.

    Gruss
    Henry

    Mittwoch, 15. August 2012 04:07
  • Weil ich dann für jede View-Zeile das SQL-Statement manuell setzen müsste,

    im Vergleich dazu wäre ein DataTable mit CommandBuilder und da.Update(dt)

    um einiges komfortabler.

    Alternativ hab ich mir gedacht direkt auf den Quelltabellen zu arbeiten u

    d um den entsprechenden Code-Block "Transaktionsfunktionen" zu legen zur

    Wahrung der Datenkonsistenz. Hab bisher nur von diesem Konzept gehört,

    hat vll jemand ein entsprechendes Code-Snippet parat?

    MfG


    
    • Bearbeitet Flux1989 Mittwoch, 15. August 2012 07:13
    Mittwoch, 15. August 2012 07:11
  • Wieso musst Du da für jede View Zeile das SQL Statement manuell absetzen? mit dem ExecuteNonQuery lassen sich sehr wohl Bulk Updates auf alle Zeilen, welche der Where Bedingung entsprechen, absetzen.

    Ich würde nicht mit den Table Adaptors arbeiten, das ist kompilzierter und wird wohl kaum irgendwelche Vorteile bringen.

    Gruss

    Henry

    Mittwoch, 15. August 2012 10:16
  • mit dem ExecuteNonQuery lassen sich sehr wohl Bulk Updates auf alle Zeilen, welche der Where Bedingung entsprechen, absetzen.

    OK, angenommen ich hab ne Tabelle T, mit den Spalten id (autoincrement) und v1 (text) und v2 (text), wobei v2 erstmal nur NULLs enthält:

    1 a

    2 b

    3 c

    Angenommen der Algorithmus für v2 lautet:

    if(v1 < "m")

      return (v2 = "m")

    else

      return (v2 = v1);

    Wenn ich nun die Werte für v2 in jeder Zeile einzeln anhand eines (für alle Zeilen einheitlichen) Algorithmus bestimmen will, wie muss ich dann das SQL-Statement formulieren? v2_var berechne ich momentan in jedem Zeilendurchlauf meines DataReaders:

    //Verbindung aufgebaut und Daten aus View in DataReader geladen
    while(dr.Read())
    {
     v2_var = (dr["v1"] < "m" ? "m" : dr["v1"])
     string cmdStr = "UPDATE T SET v2 = " + v2_var + " WHERE id = " + dr["id"];
     cmd.CommandText = cmdStr;
     cmd.ExecuteNonQuery();
    }
    Ein BulkUpdate setzt voraus, dass die upzudatenden Werte vorher bekannt sein müssen..


    • Bearbeitet Flux1989 Mittwoch, 15. August 2012 12:34
    Mittwoch, 15. August 2012 12:31
  • Ich verstehe nicht, wieso Du dazu einen DataReader brauchst. Du willst in der Tabelle T die Spalte v2 abhängig vom Inhalt in v1 ändern. Mit deinem Beispiel wären das 2 Bulk UPDATE Statement, die Du nacheinander abschicken kannst.

    Ich gehe davon aus, dass cmd.Connection gesetzt ist. Vergiss' mal alles mit dem Datareader und versuche Folgendes:

    cmd.CommandText = "UPDATE T SET v2 = 'm' WHERE v1 < 'm'"; cmd.ExecuteNonQuery(); cmd.CommandText = "UPDATE T SET v2 = v1 WHERE v1 >= 'm'"; cmd.ExecuteNonQuery();

    Allenfalls kapselst Du das ganze noch in eine Transaktion und nun sollte die Tabelle T die gewünschten Werte beinhalten. Nun kannst Du, falls Du noch einen Datareader benötigst, diesen öffnen und einlesen.

    Gruss

    Henry


    Freitag, 17. August 2012 06:47
  • Ich Stimme Henry zu,

    Hier ein Beispiel:

    public void DatenAktualisieren() {
             // Aktualisiert Daten in der Datenbank
             // Variablen deklarieren
             string constr;
             // Beinhaltet den Connectionstring zur Datenbank
             OleDBConnection conn;
             // Ist die Datenleitung zur Datenbank
             string strsql;
             // Beinhaltet den Befehl an die Datenbank
             // Verbindung zur Datenbank festlegen
             // Variert leicht, je nachdem welcher Datenbanktyp
             // Weitere Hilfe unter www.connectionstrings.com
             constr = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\\myFolder\\myAccess2007file.accdb;Persist Security Inf" +
             "o=False;";
             conn = new SqlConnection(constr);
             // Datenleitung wird geöffnet
             conn.Open();
             // Datenbankbefehl wird definiert
             strsql = "UPDATE Bespieltabelle SET Anrede = 'Frau', Nachname = 'Mustermann' WHERE Kundennummer=4711;"
             SqlCommand cmd = new SqlCommand(strsql, conn);
             // Befehlsobjekt ausführen
             cmd.ExecuteNonQuery();
             // Verbindung zur Datenbank schliessen
             conn.Close();
         }
     

    Gruß

    Michael

    Mittwoch, 29. August 2012 15:34
  • Das Problem ist leider noch nicht gelöst. Habs bisher mit nem Datareader gemacht und für jede gelesene Zeile ein cmd.ExecuteNonQuery gemacht - mit katastrophaler performance.

    Die Situation:

    Ein DataTable gefüllt mit Daten aus einem View, auf jede Zeile des DataTables wurde ein Algorithmus angewendet.

    Nun möchte ich die veränderten Felder zurückschreiben (Update). Bekanntlich ist der OleDbCommandBuilder nicht dazu in der Lage bei mehreren Quelltabellen.

    Die Situation vereinfacht sich insofern, als dass nur Daten EINER Quelltabelle geändert und somit zurückgeschrieben werden müssen.

    Wie gehe ich da am besten vor? Habe Schwierigkeiten das (Bulk-) Update-Kommando zu formulieren.

    Update Quelltabelle SET {alle veränderten Spalten} WHERE {der PK von Quelltabelle ist eine Spalte im DataTable}

    Gruß

    Flux89


    • Bearbeitet Flux1989 Freitag, 7. September 2012 14:02
    Freitag, 7. September 2012 14:01
  • Verzichte einfach auf den Data Reader, der hat bei einem SQLCommand wenig bis gar nichts nichts zu suchen. Die Primärschlüssel, die Du in den Data Reader eingelesen hast müssen ja bestimmten Kriterien entsprechen, also z.B.

    SELECT DeinPK
      FROM DeineTabelle
     WHERE irgendwas = irgendwasAnderes

    Beschreibe besser, was Du in den Data Reader eingelesen hast. Es gibt mit grosser Wahrscheinlichkeit einen Bulk Update, der das SQL Statemet, mit dem Du den Datareader einliest, integriert.

    Im obigen Fall wäre das Statement dann

    UPDATE DeineTabelle
     SET DeinFeld = wasAuchImmer
     WHERE DeinPK IN (
      SELECT DeinPK
        FROM DeineTabelle
        WHERE irgendwas = irgendwasAnderes)

    Weise dann das SQL Statement dem  SQLCommand.CommandText zu und führe ExecuteNonQuery aus.

    Gruss

    Henry

    Freitag, 7. September 2012 14:52
  • Hi Henry,

    ich versuche das Szenario noch etwas genauer zu beschreiben:

    Die View kombiniert zwei Tabellen T1 und T1, welche eine 1 : 1 Beziehung haben, d.h. jeder PK von T1 kommt maximal in einer Zeile vor. Nun betrachte ich jede Zeile des View und veraendere Felder in T1 anhand von Feleder in T2.

    Schliesslich moechte ich T1 updaten (pro View-Zeile sind es mehrere Felder, die in T1 geschrieben werden sollen).

    Bin mir zwar nicht sicher, ob es ein Bulk-Update-Kommand gibt, aber ich versuch mich mal:

    UPDATE T1
    SET c1 = ds.Tables["T1joinT2"].Columns["col1"], c2 = ds.Tables["T1joinT2"].Columns["col1"]
    WHERE T1.id IN ds.Tables["T1joinT2"].Columns["Tid"]
    

    Sehe ehrlich gesagt nicht, wie ich DataTable und SQL-Updatestatement zusammenbringen kann ??

    Danke

    Flux89


    • Bearbeitet Flux1989 Freitag, 7. September 2012 18:07
    Freitag, 7. September 2012 18:04
  • Hallo Flux98

    Wir kommen so nicht weiter. Sorry. Solange Du an der DataTable Variable festhälst und nicht verraten willst, was da drin ist, werden wir keine Lösung finden. Du musst, wenn Du einen Bulk Update machen willst, auf diese Variable verzichten. Es muss alles aus der Datenbank kommen, in der Du die Daten ändern willst, weil der Bulk Update ja nicht auf Deine lokalen Programm Variablen zugreifen kann.

    Schreibe zuerst mal eine Query, welche das Wunsch-Ergebnis in Feldern ausgibt, indem es diese aus den Werten in T2 ermittelt. In der Where Bedingung musst Du hier dann eben wie in meinem obigen Beispiel das SELECT Statement drin haben, mit dem Du den DataTable füllst, nicht den Data Table selber.

    Wenn Du soweit bist, dann änderst Du die Abfrage in einen Update (über den Wizzard) und wählst als zu ändernde Tabelle die Tabelle T1 aus. Dann musst Du noch ausfüllen, in welche Felder die Wunsch Ergebnisse in T1 weggeschrieben werden sollen und nun ist der Bulk Update fertig.

    Gruss

    Henry

    Montag, 10. September 2012 02:47
  • Hi Henry, ich habs letztendlich so gemacht:

    Per Datareader die Query lesen, dabei pro zeile ein DataTable mit den Ergebnisspalten beschreiben und dieses Datatable am schluss updaten. Die Performance-Steigerung liegt im 1000er-Bereich.

    Trotzdem vielen dank für deine Mühe. Leider konnte ich deinem letzten Post inhaltlich nicht folgen, iwie versteh ichs net richtig, schätze ich müsste die lösung einmal gesehen habe, bevor ichs selber machen könnte...

    Gruß

    Flux89

    • Bearbeitet Flux1989 Donnerstag, 13. September 2012 17:31
    Donnerstag, 13. September 2012 17:30