Autor |
Beitrag |
Romy
Hält's aus hier
Beiträge: 8
Win XP
VB, Java, C#
|
Verfasst: Mo 29.12.08 13:41
Hallo,
wie kann ich den Inhalt aus einer generierten Textbox mit einem sql-Befehl in ein Excel-Sheet schreiben?
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: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39:
| private void cmdChemErfSp_Click(object sender, EventArgs e) { strQuelle = "D:\\SCHULE HAK\\Maturaprojekt\\CH_Chemialiendatenbank1.0\\CH_Chemialiendatenbank1.0\\bin\\Debug\\Chemikalien.xls";
cn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + strQuelle + ";Extended Properties=Excel 8.0"; sql = "Select * FROM [Chemikalien$]";
conn = new OleDbConnection(cn); da = new OleDbDataAdapter(sql, conn); ds = new DataSet(); conn.Open(); da.Fill(ds, "Chemikalien"); conn.Close();
foreach (Control ctl in groupBox2.Controls) { TextBox box = ctl as TextBox; if (box != null) { string content = box.Text; } }
} |
Es geht um den auskommentierten sql-Befehl! Wie kann ich jetzt die Textboxen ansprechen um die Werte speichern zu können?
Danke für eure Hilfe,
lg Romy
|
|
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: Mo 29.12.08 14:39
Hallo Romy,
welche Beziehung haben die Inhalte der DataTable "Chemikalien" mit denen der TextBoxen? Entsprechen die Felder, die Du im Insert-Befehl vorgesehen hast, genau denen des Select-Befehls? Willst Du mit einem Insert-Befehl genau einen Datensatz neu anlegen, oder geht es eigentlich um eine (beliebige) Anzahl von Datensätzen?
Grundsatz unter ADO.NET ist die Trennung zwischen Datenbank (hier: Excel-Sheet), Daten im Arbeitsspeicher (DataTable) und GUI (Controls, hier: Textboxen). Für die Verbindung zwischen Datenbank und Arbeitsspeicher gibt es DbDataAdapter und DbCommand, für die Verbindung zwischen DataTable und GUI gibt es spezielle Controls (z.B. DataGridView) und DataBinding (für fast beliebige Controls).
Eine allgemeine Einführung findest Du z.B. im OpenBook Visual C# Kap.25 ff. (für die Arbeit mit Excel musst Du statt der Sql-Klassen jeweils OleDb-Klassen verwenden und bei DbCommand.Parameters '?' statt '@'+Namen schreiben).
Konkret: Unter der Voraussetzung, dass die Inhalte der TextBoxen von groupBox2 zusammen als ein Datensatz an Excel geschickt werden und es sich immer nur um eine Zeile handelt, geht es etwa so - dafür ist ein einzelner DbCommand sinnvoll, kein DbDataAdapter:
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:
| strQuelle = @"D:\SCHULE HAK\Maturaprojekt\CH_Chemialiendatenbank1.0\CH_Chemialiendatenbank1.0\bin\Debug\Chemikalien.xls"; connString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + strQuelle + ";Extended Properties=Excel 8.0";
private void SaveNewChemical(object sender, EventArgs e) { using(OleDbConnection conn = new OleDbConnection(connString)) { string sql = "INSERT INTO Chemikalien$ " + "(Name, [IUPAC Name], Trivialnamen, Summenformel, Sicherheitsdatenblatt, " + " Supplier, Lagerung, Labor, Konsistenz, Anmerkungen) VALUES " + "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"; OleDbCommand cmd = new OleDbCommand(sql, conn); cmd.Parameters.Add("@Name", OleDbType.VarChar, 35).Value = (groupBox2.Controls["txt0"] as TextBox).Text; cmd.Parameters.Add("@PeriodicOrder", OleDbType.Integer).Value = int.Parse( (groupBox2.Controls["txt3"] as TextBox).Text ); conn.Open(); cmd.ExecuteNonQuery(); } } |
Das meiste dürfte sich von alleine erklären. Weitere Hinweise:
Eine DbConnection soll immer nur kurzfristig geöffnet sein (das hattest Du schon beim Einlesen beachtet). Deshalb ist es sinnvoll, den ConnectionString einmalig "global" zu registieren und dann immer wieder zu benutzen.
conn.Open und conn.Close werden beim DbDataAdapter in der Regel nicht benötigt, das macht der selbst. Noch sicherer ist der using-Block wie in meinem Beispiel.
DbCommand.Parameters ist eine sichere Variante für das Einfügen variabler Inhalte. Dein Versuch ist zwar möglich, aber auch nur bei Texten und außerdem umständlich und fehleranfällig. In dieser Situation habe ich jeweils den OleDbType mit Maximallänge verwendet; es gibt andere Varianten (vor allem AddWithValue). Der Text kann aber erst dann geholt werden, wenn wir wirklich eine TextBox haben; das erledige ich in der "inneren Klammer" mit " as". Eigentlich gehört hierher noch eine Prüfung "ungleich null"; aber darauf verzichte ich (denn wir wissen ja, welche Controls die GroupBox hat).
Bei Zahlen und Datumsangaben muss noch aus TextBox.Text eine Wert des betreffenden Typs gemacht werden; dazu verwende ich int.Parse. Auch das ist riskant; z.B. führt ein leeres Feld zu einer Exception. (Dabei hilft das Validating-Ereignis aus meinem Vorschlag unter Generierte Felder ansprechen.)
Ich hoffe, ich habe Dich mit diesen ganzen Informationen nicht zu sehr verwirrt.
Gruß Jürgen
|
|
Romy 
Hält's aus hier
Beiträge: 8
Win XP
VB, Java, C#
|
Verfasst: Mo 29.12.08 15:44
Danke für deine Antwort!
Ich hab es laut deiner Anleitung versucht, aber ich hab noch einige Fragen dazu.
Zuerst aber mal zu deiner Frage, also ich hab ein Formular zur Chemikalienanlegung erstellt, die Felder sind nach dem Inhalt des Excel-Sheets (Name, IUPAC Name, etc.) generiert.
Im Hauptformular habe ich eine Übersicht mit allen vorhandenen Chemikalien die ich mit "SELECT * FROM ..." einlese, das Formular mit der Chemikalienanlegung ist ein eigener Bereich.
Es handelt sich also sogesehen um ein Formular in welches Daten eingegeben werden, diese werden gespeichert und dann kann sofort wieder ein neuer Datensatz eingegeben werden.
Wechselt man ins Hauptformluar zurückt sollte der neue Datensatz angezeigt werden.
Ich hab alles laut deiner Anleitung gemacht und für alle Felder deinen Befehl ausgeführt.
Zum Datenspeichern habe ich einen CommandButton (cmdChemErfSp), beim Click-Ereigniss habe ich SaveNewChemical(conn, e); aufgerufen. Welche Parameter muss ich übergeben?
Passt das try-catch oder muss ich zusätzlich noch irgendetwas beachten?
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: 29: 30: 31: 32: 33: 34:
| private void SaveNewChemical(object sender, EventArgs e) { strQuelle = @"D:\SCHULE HAK\Maturaprojekt\CH_Chemialiendatenbank1.0\CH_Chemialiendatenbank1.0\bin\Debug\Chemikalien.xls"; string connString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + strQuelle + ";Extended Properties=Excel 8.0";
using (OleDbConnection conn = new OleDbConnection(connString)) { string sql = "INSERT INTO Chemikalien$ " + "(Name, [IUPAC Name], Trivialnamen, Summenformel, Sicherheitsdatenblatt, " + " Supplier, Lagerung, Labor, Konsistenz, Anmerkungen) VALUES " + "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"; OleDbCommand cmd = new OleDbCommand(sql, conn); cmd.Parameters.Add("@Name", OleDbType.VarChar, 35).Value = (groupBox2.Controls["txt0"] as TextBox).Text; cmd.Parameters.Add("@[IUPAC Name]", OleDbType.VarChar, 35).Value = (groupBox2.Controls["txt1"] as TextBox).Text; cmd.Parameters.Add("@Trivialnamen", OleDbType.VarChar, 35).Value = (groupBox2.Controls["txt2"] as TextBox).Text; cmd.Parameters.Add("@Summenformel", OleDbType.VarChar, 35).Value = (groupBox2.Controls["txt3"] as TextBox).Text; try { conn.Open(); cmd.ExecuteNonQuery(); } catch(Exception exp) { } |
So funktioniert es derzeit noch nicht, ich bekomme aber auch keine Fehlermeldung (der Datensatz wird nicht gespeichert)!
Danke im Voraus!
Lg Romy
|
|
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: Mo 29.12.08 17:45
Hallo Romy,
Romy hat folgendes geschrieben : | das Formular mit der Chemikalienanlegung ist ein eigener Bereich.
Es handelt sich also sogesehen um ein Formular in welches Daten eingegeben werden, diese werden gespeichert und dann kann sofort wieder ein neuer Datensatz eingegeben werden.
Wechselt man ins Hauptformluar zurückt sollte der neue Datensatz angezeigt werden. |
Zur Zusammenarbeit dieser Formulare sind ein paar mehr Hinweise angebracht; das muss ich aus Zeitgründen jetzt zurückstellen. Wenn Du Dich selbst damit befassen willst (und kannst): Erzeuge im Hauptformular ein DataSet/DataTable. Diese DataTable wird an das "Neu"-Formular übergeben. Ein neuer Datensatz wird in die DataTable eingetragen und steht damit im Hauptformular sofort zur Verfügung (ggf. noch DataGridView.Refresh).
Warnung: Das ist noch keine saubere Lösung, sondern nur schnell hingekritzelt!
Romy hat folgendes geschrieben : | Zum Datenspeichern habe ich einen CommandButton (cmdChemErfSp), beim Click-Ereigniss habe ich SaveNewChemical(conn, e); aufgerufen. Welche Parameter muss ich übergeben? |
Falsch. Die SaveNewChemical-Methode ist das Click-Ereignis. In der Designer.cs muss so etwas stehen:
C#-Quelltext 1:
| cmdChemErfSp.Click += new EventHandler(SaveNewChemical); |
Romy hat folgendes geschrieben : | Passt das try-catch oder muss ich zusätzlich noch irgendetwas beachten?
So funktioniert es derzeit noch nicht, ich bekomme aber auch keine Fehlermeldung (der Datensatz wird nicht gespeichert)! |
Das ist auch klar, denn der leere catch-Block unterdrückt jede Fehlermeldung.
Einen Fehler sehe ich nicht; deshalb ist es nötig, dass Du Dir eine Fehlermeldung zeigen lässt:
C#-Quelltext 1: 2:
| MessageBox.Show(exp.ToString(), "Fehler beim Speichern"); |
exp.ToString zeigt erheblich mehr Informationen an als exp.Message.
Gruß Jürgen
|
|
Romy 
Hält's aus hier
Beiträge: 8
Win XP
VB, Java, C#
|
Verfasst: Mo 19.01.09 13:38
Hallo,
ich habe mittlerweile schon einige Testversuche gestartet und ein komplett neues System "entwickelt"; da ich mit dem Vorschlag leider nicht wirklich klar kam und auch keine Ergebnisse geliefert wurden.
Nur das Problem ist jetzt, ich bekomme stets die Fehlermeldung, dass es einen Syntaxfehler in der INSERT INTO-Anweisung gibt.
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:
| private void SaveNewChemical(object sender, System.EventArgs e) { strQuelle = @"D:\SCHULE HAK\Maturaprojekt\CH_Chemialiendatenbank1.0\CH_Chemialiendatenbank1.0\bin\Debug\Chemikalien.xls"; string connString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + strQuelle + ";Extended Properties=Excel 8.0";
db.dbOpen(); string sql = "INSERT INTO Chemikalien$ ("; for (int i = 0; i < dgv.Columns.Count; i++) { sql += "[" + dt.Columns[i].ColumnName.ToString() + "],"; } sql = sql.Substring(0, sql.Length - 1); sql += ") VALUES (\"";
for (int i = 0; i < dgv.Columns.Count; i++) { TextBox box = this.groupBox2.Controls["txt" + i.ToString()] as TextBox; sql += box.Text + "\",\""; } sql = sql.Substring(0, sql.Length - 2) + ")"; MessageBox.Show(sql); db.Ausfuehren(sql); } |
Weiters habe ich in einer seperaten Klasse folgendes definiert:
C#-Quelltext 1: 2: 3: 4: 5:
| public int Ausfuehren(string sql) { cmd = new OleDbCommand(sql, verbindung); return cmd.ExecuteNonQuery(); } |
Ich habe schon versucht die Werte mit Hochkomma zu übergeben, funktioniert aber nicht, doch diese Version mit "\ funktioniert auch nicht.
Wenn irgendwer den Fehler bzw. eine Problemlösung findet, bitte sagt mir Bescheid!
Danke, lg Romy
|
|
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: Mo 19.01.09 15:03
Benutze für variable Inhalte eines SQL-Befehls niemals String-Verknüpfung, sondern immer DbParameter!
Kurze Begründung hier: Das Problem mit den Hochkommata wird vom OleDb-Provider geregelt; Du brauchst Dich nicht darum zu kümmern.
Wie Du die folgende Konstruktion am besten in Deine Db-Klasse einbaust, habe ich jetzt nicht überlegt. Ich habe stillschweigend die Namen der TextBoxen geändert, nämlich auf "txt" + ColumnName. Das empfinde ich als logischer und sachgerechter.
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:
| string colnames = String.Empty; string colparams = String.Empty; foreach(DataColumn col in dt.Columns) { colnames += " [" + col.ColumnName + "], "; colparams += "?, "; } string sql = "INSERT INTO Chemikalien$ (" + colnames.Substring(0, colnames.Length - 2) + ") VALUES (" + colparams.Substring(0, colparams.Length - 2) + ");";
OleDbCommand cmd = new OleDbCommand(sql, connection); foreach(DataColumn col in dt.Columns) { TextBox box = groupBox2.Controls["txt" + col.ColumnName] as TextBox; cmd.Parameters.Add("@" + col.ColumnName, OleDbType.VarChar, 50).Value = box.Text; } |
Dieses Verfahren vermeidet jedenfalls viele "gängige" Fehler; das möchte ich Dir deshalb unbedingt ans Herz legen. Ob es Dein Problem wirklich beseitigt, ist aber nicht sicher. Beispielsweise weiß ich nicht, ob der Spaltenname wirklich in "[]" eingebunden werden soll oder ob (wie beim Tabellennamen) ein '$' dazugehört. Auf jeden Fall kannst Du jetzt im Debugger einen klaren CommandText erkennen und kommst damit vermutlich weiter.
Gruß Jürgen
|
|
Romy 
Hält's aus hier
Beiträge: 8
Win XP
VB, Java, C#
|
Verfasst: Di 03.02.09 14:55
Danke für eure großartige Hilfe!
Ich hab es endlich geschafft, meine Daten zu speichern!
Ein besonders großes Dankeschön geht an JüTho, danke!
Lg Romy
|
|
|