Entwickler-Ecke

Datenbanken (inkl. ADO.NET) - Datenbank über DataSet aktualisieren


Orothred - Mi 21.11.07 16:10
Titel: Datenbank über DataSet aktualisieren
Hi!

Ich habe eine Form mit einem DataGrid. In dieses DataGrid lese ich über ein DataSet eine Tabelle aus einer SQL-Datenbank ein.

Jetzt kann ich ja in meinem DataGrid Änderungen an den Daten vornehmen.

Dann will ich den gesamten Inhalt vom DataGrid wieder zurück in die Tabelle der SQL-Datenbank schreiben. Wie mach ich das?


Kha - Mi 21.11.07 16:20

Genau so, wie du die Daten in das DataSet geholt hast: über einen (typisierten) DataAdapter.


Orothred - Mi 21.11.07 16:25

also da.Fill(ds) und dann einfach ne sql-connection mit dem dataadpater machen oder wie?


Kha - Mi 21.11.07 17:22

naja, "Fill" ist zum Füllen da. Vielleicht findest du ja eine etwas passendere Mehode ;) .


JüTho - Mi 21.11.07 18:19

Khabarakh's Vorschlag solltest Du Dir zu Herzen nehmen: Öffne die SDK-Doku (die sollte sowieso das wichtigste Hilfsmittel sein - noch wichtiger als alle Foren, in denen Du grundlegende Fragen stellst) zu einem Stichwort - jetzt z.B. DataAdapter - und schau nach, welche Eigenschaften und Methoden angeboten werden.

Für die Grundlagen zur Datenverarbeitung kann ich verweisen auf OpenBook Visual C# Kap.26 [http://www.galileocomputing.de/openbook/visual_csharp/].

Jürgen


Orothred - Do 29.11.07 09:21

hm, leider bin ich hier immer noch net weiter gekommen. im moment tue ich folgendes:

ich stelle eine verbindung zum sql-server her.
ich erstelle ein sqlcommand, das ich mit einem select-command fülle, dass alle spalten aus einer tabelle auswählt.
nun erstelle ich einen dataadapter und übergebe ihm das sqlcommand
nun erstelle ich einen sqlcommandbuilder, und übergebe der eigenschaft dataadapter.update-command den wert sqlcommandbuildeer.getupdatecommand.
nun versuche ich mit dataadatper.update mein dataset in die datenbank zu schreiben.

nicht passiert...

ich bin am verzweifeln ^^


JüTho - Do 29.11.07 10:49

user profile iconOrothred hat folgendes geschrieben:

nun versuche ich mit dataadatper.update mein dataset in die datenbank zu schreiben.

nicht passiert...

Das Verfahren als solches klingt vernünftig. Aber sind auch alle "Rahmenbedingungen" erfüllt? Der DbCommandBuilder kann nur arbeiten, wenn der SelectCommand sich auf genau eine Tabelle bezieht (JOINs sind also verboten) und der PrimaryKey im SELECT enthalten ist. DbDataAdapter.Update() wertet den RowState der betroffenen Zeilen aus; sind denn auch wirklich welche geändert worden?

Hinweis für den Debugger: UpdateCommand kontrollieren, RowState kontrollieren, Rückgabewert der Update-Methode prüfen.

Gruß Jürgen


Orothred - Do 29.11.07 10:56

achso, stimmt, ich bekomme noch die fehlermeldung, das das select-command nicht initialisiert wurde...

was kann ich denn dagegen tun? weil an der tabelle selbst darf ich net rumspielen, die liegt auf den sql-servern von der firma....da hab ich ja nix verloren ^^


JüTho - Do 29.11.07 11:04

Ist doch offensichtlich: Du musst den ursprünglichen Select-Command so ändern, dass er die Bedingungen des DbCommandBuilder erfüllt, und dann dem DbCommandBuilder zuweisen ("initialisieren"). Jürgen


Orothred - Do 29.11.07 11:06

ich glaub ich bin zu doof dafür ^^

wie weiß ich das dem DBCommandBuilder zu?


JüTho - Do 29.11.07 13:09

Guckst Du in die SDK-Doku, dann verstehe (neben der Anleitung) das Beispiel bei der SqlCommandBuilder-Klasse. Jürgen


Orothred - Do 29.11.07 14:33

Ok, die Funktionsweise hab ich jetzt verstanden, aber es funktioniert immer noch nicht.

Hier mal mein Code


C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
private void btnOK_Click(object sender, EventArgs e)
      {
         SQLHelper sqlhelper = globalCommonData.DefaultDBConnection;
         DbConnection dbConnection = sqlhelper.GetConnection();
         SqlDataAdapter da = new SqlDataAdapter();
         da.SelectCommand = new SqlCommand("SELECT * FROM JITNT.tour_plan");
         SqlCommandBuilder builder = new SqlCommandBuilder(da);
         da.Update(globalDS);
      }


SQLHelper ist eine fertige Klasse aus einem Projekt, das wir hier in der Firma für Datenbankanwendungen benutzen. Sie enthält verschieden Funktionen für den Datenbankzugriff, unter anderem die hier verwendete Funktion GetConnection, mit der eine Verbindung zur Datenbank hergestellt wird. Den Code darf ich auch aber leider nicht zeigen.
So, nun hab ich in der SDK gelesen, dass ich dem CommandBuilder das Connection-Objekt überegeben soll. Der CommandBuilder will aber eine SQLConnection, wir verwenden hier eine DbConnection. Wie krieg ich das Ding jetzt zum Laufen?

Moderiert von user profile iconjasocul: Code- durch C#-Tags ersetzt


JüTho - Do 29.11.07 16:04

Ab hier kann Dir niemand helfen, das musst Du selbst untersuchen, weil Du nur den SQLHelper verwenden kannst. Dazu kannst Du den Debugger verwenden oder Roeder's Reflector [http://www.aisto.com/roeder/dotnet/].

Das Problem liegt darin, dass alle Sql-Klassen abgeleitet wurden von den entsprechenden Db-Klassen. Wenn sqlhelper.GetConnection() eine SqlConnection liefert, kann diese entsprechend verwendet werden, z.B. mit dem as-Parameter. Aber wenn es sich um eine andere DbConnection handelt, dann führt dies zu Exceptions.

Alternative: Du kannst anstelle der Sql-Klassen selbst ausschließlich Db-Klassen verwenden. Dann bist Du aber beschränkt auf die Minimalfunktionen aller Db-Klassen. Beispiel:

C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
private void btnOK_Click(object sender, EventArgs e)
      {
         SQLHelper sqlhelper = globalCommonData.DefaultDBConnection;
         DbConnection dbConnection = sqlhelper.GetConnection();
         DbDataAdapter da = new DbDataAdapter();
         da.SelectCommand = new DbCommand("SELECT * FROM JITNT.tour_plan");
         DbCommandBuilder builder = new DbCommandBuilder(da);
         da.Update(globalDS);
      }

Gruß Jürgen


Orothred - Do 29.11.07 17:17

von den Klassen DbDataAdapter, DbCommand und DbCommandBuilder darf ich keine Instanzen bilden sagt er mir...

so ein sch... da!


JüTho - Do 29.11.07 18:30

Das hatte ich jetzt nicht untersucht. Aber auch dann geht es, allerdings wird es noch (schwieriger) umständlicher:

C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
//  erzeuge die Verbindung zum DataProvider und zur Datenbank
DbProviderFactory dataFactory 
    = DbProviderFactories.GetFactory("System.Data.SqlClient");
DbConnection conn = dataFactory.CreateConnection();
DbDataAdapter da = dataFactory.CreateDataAdapter();  
DbCommandBuilder bld = dataFactory.CreateCommandBuilder();
//  usw.

So etwas funktioniert wirklich! Die Frage ist, ob Du Dich so sehr in die Details vertiefen willst (zumal Du doch eher Anfänger zu sein scheinst).

Jürgen


Orothred - Mo 03.12.07 08:33

So sieht mein Code jetzt aus:


C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
// Instanzen der Db-Klassen erzeugen
         DbProviderFactory dataFactory = DbProviderFactories.GetFactory("System.Data.SqlClient");
         DbConnection dbConnection = dataFactory.CreateConnection();
         DbDataAdapter da = dataFactory.CreateDataAdapter();
         DbCommand cmd = dataFactory.CreateCommand();
         DbCommandBuilder builder = dataFactory.CreateCommandBuilder();
         
         SQLHelper sqlhelper = globalCommonData.DefaultDBConnection;
         dbConnection = sqlhelper.GetConnection();
         cmd.CommandText = "SELECT * FROM JITNT.tour_plan";
         da.SelectCommand = cmd;
         builder.DataAdapter = da;
         da.Update(globalDS);



funktionieren tut das hochladen immer noch nicht....

Moderiert von user profile iconjasocul: Code- durch C#-Tags ersetzt


Orothred - Mo 03.12.07 08:48

ok, hatte ja noch kein update-command erzeugt.

nachdem ich die da.UpdateCommand eigenschaft mit builder.GetUpdateCommand belegt hatte, bekam ich die fehlermeldung, das die DataAdapter.SelectCommand.Connection-Eigenschaft nicht initialisiert wird.

Also hab ich sie mit dbConnection initialisiert.

Jetzt bekomme ich wieder die Fehlermeldung, das die DataAdapter.SelectCommand-Eigenschaft nicht initialisiert ist. Aber ich initialisiere sie doch...

Hier der aktuelle Code:


C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
         // Instanzen der Db-Klassen erzeugen
         DbProviderFactory dataFactory = DbProviderFactories.GetFactory("System.Data.SqlClient");
         DbConnection dbConnection = dataFactory.CreateConnection();
         DbDataAdapter da = dataFactory.CreateDataAdapter();
         DbCommand cmd = dataFactory.CreateCommand();
         DbCommandBuilder builder = dataFactory.CreateCommandBuilder();
         
         SQLHelper sqlhelper = globalCommonData.DefaultDBConnection;
         dbConnection = sqlhelper.GetConnection();
         cmd.CommandText = "SELECT * FROM JITNT.tour_plan";
         da.SelectCommand = cmd;
         da.SelectCommand.Connection = dbConnection;
         da.UpdateCommand = builder.GetUpdateCommand();
         da.Update(globalDS);


Moderiert von user profile iconjasocul: Code- durch C#-Tags ersetzt


JüTho - Mo 03.12.07 10:01

Hallo,

hast Du auch verstanden, was ich Dir als Weg angeboten habe, oder hast Du es nur kopiert? Dein letzter Code enthält folgende Problemstellen:

Zeile 3: dbConnection wird erzeugt, aber noch ohne Details.
Zeile 4: da wird erzeugt, aber ohne Verbindung mit dbConnection.
Zeile 5, 6: ebenso
Zeile 9: dbConnection wird nochmals erzeugt, und zwar vermutlich mit den Details, die der sqlhelper liefert.

Außerdem kommt es zum Teil auf die Reihenfolge der Zuweisungen an. Das musst Du in den Anleitungen (z.B. OpenBook) oder SDK-Doku nachprüfen. Meine Vermutungen lauten: Zuerst cmd.Connection festlegen, dann cmd dem DbDataAdapter zuweisen. Außerdem weiß ich nicht auswendig, wann der CommandBuilder aktiv wird; vielleicht muss zunächst da.Fill() ausgeführt werden.

Jürgen


Orothred - Mo 03.12.07 10:41

hm, meiner meinung nach übergebe ich hier


C#-Quelltext
1:
dbConnection = sqlhelper.GetConnection();                    


die details an dbConnection, erzeugt wird es allerdings nicht nocheinmal, sondern nur mit werten versorgt.

des weiteren wird hier


C#-Quelltext
1:
da.SelectCommand.Connection = dbConnection;                    


der DataAdapter mit den Werten von dbConnetion versorgt.


daraus würde folgen das der CommandBuilder hier


C#-Quelltext
1:
da.UpdateCommand = builder.GetUpdateCommand();                    


aktiv wird, mit den Details aus dem DataAdapter.

und hier


C#-Quelltext
1:
da.SelectCommand = cmd;                    


wird meiner meinung nach das SelectCommand initialisiert. Allerdings behauptet das Programm das gegenteil ^^

Korrigiere mich bitte wenn meine vermutungen falsch sind ^^


und ja, ich hab verstanden, was du mir als weg angeboten hast. hab mich über DbProviderFactory in MSDN informiert und es danach benutzt. NICHT abgeschrieben ^^

Moderiert von user profile iconjasocul: Code- durch C#-Tags ersetzt


Orothred - Mo 03.12.07 12:07

hab ihn mittlerweile soweit das er ein UPDATE-Command zusammenbaut. hab noch


C#-Quelltext
1:
builder.DataAdapter = da;                    


eingefügt, dann gings.


das update-command, das er baut, wenn ich eine zeile lösche oder editiere ist immer gleich und lautet:


C#-Quelltext
1:
UPDATE [JITNT].[tour_plan] SET[key] = @p1, [ts_start_est] = @p2, [dest_code] = @p3, [status] = @p4, [session_create] = @p5, [lasupdate] = @p6, [user] = @p7, [payload_cars] = @p8 WHERE (([id] = @p9) AND ([key] = @p10) AND ([ts_start_est] = @p11) AND ([dest_code] = p@12) AND ([status] = @p13) AND ([session_create] = @p14) AND ([lastupdate] = @p15) AND ([user] = @p16) AND ([payload_cars) = @p17))                    


updaten tut er immer noch nix....

Moderiert von user profile iconjasocul: Code- durch C#-Tags ersetzt


Orothred - Di 04.12.07 08:26

so, ich schon wieder.

änderungen in den bestehenden datensätzen speichert er mittlerweile, wenn ich allerdings neue datensätze hinzufüge oder bestehende löschen, dann werden diese änderungen ignoriert.

hier nochmal der jetzige code:


C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
         dbConnection = sqlhelper.GetConnection();
         cmd.CommandText = "SELECT * FROM JITNT.tour_plan";
         builder.DataAdapter = da;
         da.SelectCommand = cmd;
         da.SelectCommand.Connection = dbConnection;
         da.UpdateCommand = builder.GetUpdateCommand();
         da.InsertCommand = builder.GetInsertCommand();
         da.DeleteCommand = builder.GetDeleteCommand();
         da.Update(globalDS);



was muss ich noch tun, damit auch diese änderungen gespeichert werden?

Moderiert von user profile iconjasocul: Code- durch C#-Tags ersetzt


jasocul - Di 04.12.07 09:41

Hallo Orothred,

wie Dir vielleicht aufgefallen ist, habe ich in jedem Deiner Beiträge die Code-Tags durch C#-Tags ersetzt. Vielleicht könntest Du fortan selbst darauf achten, die richtigen Tags zu nehmen.

Gruß,
Jasocul.