Autor |
Beitrag |
Kanalpiroge
Hält's aus hier
Beiträge: 6
Win XP
C# (VS 2008 Express)
|
Verfasst: Do 22.10.09 13:31
Hallo!
Ich bin C# Newbee und experimentiere gerade mit Datenbindung herum, weil ich ein Datenbank Frontend basteln möchte.
Mein erstes Teilziel ist, einen Datensatz in einem Form anzuzeigen und diesen verändern und speichern zu können. Dabei möchte ich erst mal auf den ganzen Schnickschnack verzichten, den die IDE mir automatisch generiert, damit ich noch halbwegs nachvollziehen kann, was da passiert.
Ich benutze kein DataSet sondern nur eine DataTable, weil ich nicht durch die Tabelle navigieren möchte sondern immer nur gezielt einen Datensatz auslesen und bearbeiten. Die Daten binde ich an Textfelder.
Das Anzeigen der Daten funktioniert auch ganz gut, nur das Update haut nicht hin.
C#-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28:
| private OleDbConnection dbConnection; private OleDbDataAdapter daDetails; private DataTable dtUserDetails; private OleDbCommandBuilder commandBuilder;
public Form1() { dbConnection = new OleDbConnection(connectionString); daDetails = new OleDbDataAdapter("SELECT * FROM `User` WHERE user_id = ?", dbConnection); daDetails.SelectCommand.Parameters.Add("ID", OleDbType.Integer);
commandBuilder = new OleDbCommandBuilder(daDetails);
dtUserDetails = new DataTable(); this.txtName.DataBindings.Add("Text", dtUserDetails, "name"); this.txtVorname.DataBindings.Add("Text", dtUserDetails, "vorname"); }
private void butSpeichern_Click(object sender, EventArgs e) { daDetails.Update(dtUserDetails); } |
Bin ich da auf dem Holzweg oder habe ich was wichtiges vergessen? Die Suchfunktion und das Openbook helfen mir leider nicht weiter.
Gruß,
Ralf
|
|
JüTho
      
Beiträge: 2021
Erhaltene Danke: 6
Win XP Prof
C# 2.0 (#D für NET 2.0, dazu Firebird); früher Delphi 5 und Delphi 2005 Pro
|
Verfasst: Do 22.10.09 13:59
Hallo und
Im wesentlichen könnte man es so machen. Dein Problem liegt darin, dass du auf den "Schnickschnack" verzichten willst, z.B. auf das Navigieren in der DataTable. Denn erst wenn du die Bearbeitung in einer Zeile beendest und in die nächste Zeile gehst, werden die Änderungen aus den TextBoxen in die DataTable übernommen; erst danach weiß die Update-Methode, dass etwas zu speichern ist. Diesen automatischen Zeilenwechsel gibt es bei dir nicht.
Abhilfe: Der folgende Befehl ist vor das Update zu setzen.
C#-Quelltext 1:
| dtUserDetails.Rows[0].EndEdit(); |
Aber du solltest dir von Anfang an ein paar Punkte angewöhnen.
- Connection, DataAdapter usw. werden nur innerhalb einer Methode benutzt, nämlich dann, wenn die Daten "in die Hand genommen" werden sollen.
- Die Connection soll so kurz wie möglich geöffnet und schnell wieder geschlossen werden.
- Vor allem die Connection wird in einem using-Block gekapselt. Dadurch sparst du dir Close und Dispose und bist sicher, dass sie aufgelöst ist.
- Lediglich der ConnectionString kann "global" gespeichert werden, sodass er immer sofort zur Verfügung steht.
- In der normalen Arbeit sollte das Laden der Daten keinesfalls im Konstruktor erfolgen, allenfalls im Form.Load-Ereignis. Außerdem sollte es in eine eigene Methode ausgelagert werden.
Außerdem brauchst du keine Angst vor dem DataSet zu haben. Es macht es einfacher, mit mehreren Tabellen umzugehen.
Gruß und viel Erfolg! Jürgen
|
|
Kanalpiroge 
Hält's aus hier
Beiträge: 6
Win XP
C# (VS 2008 Express)
|
Verfasst: Do 22.10.09 15:27
Hi Jürgen!
Danke für die flotte Antwort. Das hat so weit funktioniert.
Aber jetzt kriege ich die Fehlermeldung, dass das Update Statement nicht korrekt ist. Die Parameter in dem Command Objekt haben alle den Wert null. Ist da mit der Datenbindung was nicht in Ordnung?
Das DataSet werde ich mir mal eingehender anschauen. Nur die von der IDE generierten Geschichten führen ja irgendwie dazu, dass erst mal komplett alle Datensätze geladen werden und nicht nur der, den ich brauche, oder?
Gibt es vielleicht ein Buch, das diese Dinge gut und unter Umgehung der IDE Automatismen beschreibt?
|
|
JüTho
      
Beiträge: 2021
Erhaltene Danke: 6
Win XP Prof
C# 2.0 (#D für NET 2.0, dazu Firebird); früher Delphi 5 und Delphi 2005 Pro
|
Verfasst: Do 22.10.09 15:40
Hallo Ralf,
Kanalpiroge hat folgendes geschrieben : | Aber jetzt kriege ich die Fehlermeldung, dass das Update Statement nicht korrekt ist. Die Parameter in dem Command Objekt haben alle den Wert null. Ist da mit der Datenbindung was nicht in Ordnung? |
Wie sieht denn der UpdateCommand.CommandText aus (siehe Debugger)? Welche Datenbank steht dahinter, wirklich Access? Der Feldname ist natürlich ein reservierter Begriff; setz den einmal in [] statt in Hochkommata.
Kanalpiroge hat folgendes geschrieben : | Das DataSet werde ich mir mal eingehender anschauen. Nur die von der IDE generierten Geschichten führen ja irgendwie dazu, dass erst mal komplett alle Datensätze geladen werden und nicht nur der, den ich brauche, oder? |
Meinst du TableAdapter von Visual Studio? Da gibt es (soweit ich mitbekommen habe) auch die Möglichkeit eigener SELECT-Befehle mit WHERE.
Kanalpiroge hat folgendes geschrieben : | Gibt es vielleicht ein Buch, das diese Dinge gut und unter Umgehung der IDE Automatismen beschreibt? |
Tut mir leid, ich verweise auch vorzugsweise auf das OpenBook, auch wenn ich damit nicht mehr zufrieden bin. Vielleicht helfen dir die Erläuterungen und Beispiele der SDK-Doku/MSDN (erreichbar auch über Hilfe-Index) besser weiter.
Jürgen
|
|
Kanalpiroge 
Hält's aus hier
Beiträge: 6
Win XP
C# (VS 2008 Express)
|
Verfasst: Fr 23.10.09 12:10
Hi Jürgen!
JüTho hat folgendes geschrieben : |
Wie sieht denn der UpdateCommand.CommandText aus (siehe Debugger)? Welche Datenbank steht dahinter, wirklich Access? Der Feldname ist natürlich ein reservierter Begriff; setz den einmal in [] statt in Hochkommata.
|
Ja, es ist wirklich Access. Aber daran sollte es ja nicht liegen, oder? Auch wenn Access jetzt nicht die optimalste DB ist...
CommandText: UPDATE User SET name = ?, vorname = ?, abwesend = ?, vertretung = ? WHERE ((user_id = ?))
Die eckigen Klammern ändern auch nichts an dem Problem. Und, wie gesagt, wenn ich mir im Debugger die Paramter des Command Objekts anschaue (commandBuilder.GetUpdateCommand().Parameters[i].Value), dann haben die alle den Wert null.
In der DataTable (dtUserDetails.Rows[0].ItemArray) sind allerdings vernünftige Werte. Werden die vielleicht einfach nicht als Paramter eingesetzt? Muss man das irgendwie anstoßen?
JüTho hat folgendes geschrieben : |
Kanalpiroge hat folgendes geschrieben : | Das DataSet werde ich mir mal eingehender anschauen. Nur die von der IDE generierten Geschichten führen ja irgendwie dazu, dass erst mal komplett alle Datensätze geladen werden und nicht nur der, den ich brauche, oder? |
Meinst du TableAdapter von Visual Studio? Da gibt es (soweit ich mitbekommen habe) auch die Möglichkeit eigener SELECT-Befehle mit WHERE.
|
Also ich meine die automatisch generierten DataSets, wenn ich eine Datenquelle hinzufüge. Das, was da erzeugt wird, ist ja sehr umfangreis und es ist schwierig, da durchzusteigen. Und wenn ich das nutze ohne es anzupassen, werden augenscheinlich alle Datensätze in das DataSet geladen. Darum wollte ich ja noch mal von klein auf anfangen, alles manuell zu erstellen, damit ich begreife, was da überhaupt passiert.
Die Hilfe werde ich mir mal anschauen... habe auch ein Buch gefunden, das "Datenbankprogrammierung mit Visual C#" heißt. Werde mir das mal anschauen. Vielleicht hilft's ja.
Ralf
|
|
JüTho
      
Beiträge: 2021
Erhaltene Danke: 6
Win XP Prof
C# 2.0 (#D für NET 2.0, dazu Firebird); früher Delphi 5 und Delphi 2005 Pro
|
Verfasst: Fr 23.10.09 13:50
Da fehlen doch die ganzen Parameter zum Abspeichern, oder?
C#-Quelltext 1:
| daDetails.UpdateCommand.Parameters.Add(.........); |
Bei Access ist unbedingt auf die Reihenfolge zu achten; deshalb hatte ich danach gefragt. Außerdem muss die Verbindung zwischen Datenfeld und Speichern-Befehl angegeben werden. Deshalb möchte ich dich jetzt doch auf [Artikelserie] Parameter von SQL Befehlen hinweisen, auch wenn ich befürchte, dass dich das sehr beanspruchen wird (weil ich nicht "überfordern" sagen will).
Du brauchst möglicherweise eine der Alternativen zu AddWithValue, bei denen über einen Konstruktor das Feld angegeben wird.
Viel Erfolg! Jürgen
|
|
Kanalpiroge 
Hält's aus hier
Beiträge: 6
Win XP
C# (VS 2008 Express)
|
Verfasst: Fr 23.10.09 14:11
Ach so, ich dachte, der CommandBuilder baut das alles für mich, da habe ich den wohl überschätzt.
Dann setze ich die mal manuell und gucke, was passiert.
Und die Artikelserie schaue ich mir dann auch mal an.
Danke so weit!
Edit:
ich habe jetzt auf mehrere Arten versucht, die Parameter zu setzen.
Es sind allerdings schon 5 Parameter mit den Namen p1 ... p5 angelegt, so dass ich das vermutlich nicht mehr über .add() selbst erledigen muss.
1.
C#-Quelltext 1: 2: 3: 4: 5: 6: 7:
| OleDbCommand updateCommand = commandBuilder.GetUpdateCommand(); DataRow row = dtUserDetails.Rows[0]; row.EndEdit();
updateCommand.Parameters[0].Value = row["name"]; ... |
2.
C#-Quelltext 1: 2:
| updateCommand.Parameters.addWithValue("name", row["name"]); ... |
Wenn ich die Werte der Parameter beim Debuggen dann aber über
C#-Quelltext 1:
| updateCommand.Parameters[0].Value |
abrufe, sind die immer noch null. Wieso dies?
|
|
JüTho
      
Beiträge: 2021
Erhaltene Danke: 6
Win XP Prof
C# 2.0 (#D für NET 2.0, dazu Firebird); früher Delphi 5 und Delphi 2005 Pro
|
Verfasst: Fr 23.10.09 17:22
Bei der Zuordnung der Werte zu den Parametern musst du aufpassen: Entweder du verwendest die Variante 1 oder die Variante 2, aber nicht beides gemischt. AddWithValue hängt einen weiteren Parameter an!
Sonst wüsste ich allerdings auch nichts mehr. Wenn das nicht hilft, musst du wohl die gesamte Speichern-Routine einmal hierher kopieren. Jürgen
|
|
Kanalpiroge 
Hält's aus hier
Beiträge: 6
Win XP
C# (VS 2008 Express)
|
Verfasst: Di 27.10.09 12:29
So, ich habe die Ursache für das Problem gefunden:
Der CommandBuilder baut ein Update Statement a la "UPDATE Tabelle SET spalte1 = ?, spalte 2 = ? , ... WHERE ...". Wenn ich so ein Statement über C# manuell absetze, geht das auch nicht, so lange ich den Tabellennamen nicht in [] setze.
Die Frage, die sich jetzt anschließt, ist:
Kann man dem CommandBuilder irgendwie beibringen den Tabellennamen korrekt in das Statement einzusetzen?
Zuletzt bearbeitet von Kanalpiroge am Di 27.10.09 12:43, insgesamt 1-mal bearbeitet
|
|
JüTho
      
Beiträge: 2021
Erhaltene Danke: 6
Win XP Prof
C# 2.0 (#D für NET 2.0, dazu Firebird); früher Delphi 5 und Delphi 2005 Pro
|
Verfasst: Di 27.10.09 12:40
Kanalpiroge hat folgendes geschrieben : | Kann man dem CommandBuilder irgendwie beibringen den Tabellennamen korrekt in das Statement einzusetzen? |
Schau in die SDK-Doku/MSDN, dann findest du zum DbCommandBuilder zwei Eigenschaften mit folgender Beschreibung:
Zitat: | Ruft das oder die Anfangszeichen ab, die beim Angeben von Datenbankobjekten (z. B. Tabellen oder Spalten) verwendet werden sollen, deren Namen Zeichen wie Leerzeichen oder reservierte Token enthalten, oder legt diese fest. |
Lass dich nicht verwirren, dass beide Beschreibungen identisch sind (jedenfalls in meiner Version); da hat bei MS einer bei Copy&Paste nicht aufgepasst.
Besser, d.h. einfacher wäre natürlich ein anderer Tabellenname.
Gruß Jürgen
|
|
Kanalpiroge 
Hält's aus hier
Beiträge: 6
Win XP
C# (VS 2008 Express)
|
Verfasst: Di 27.10.09 12:55
Hilfe zur Selbsthilfe... pädaogisch wertvolle Antwort.
QuotePre- und Suffix lösen das Problem wunderbar. Danke Dir! 
|
|
|