Autor Beitrag
Romy
Hält's aus hier
Beiträge: 8

Win XP
VB, Java, C#
BeitragVerfasst: 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?

ausblenden volle Höhe 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:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
private void cmdChemErfSp_Click(object sender, EventArgs e)
        {
            //Eintrag in Excel-Tabelle speichern
            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();

            //Inhalt der Textboxen abfragen
            foreach (Control ctl in groupBox2.Controls)
            {
                TextBox box = ctl as TextBox;
                if (box != null)
                {
                    string content = box.Text;
                    //MessageBox.Show(content);
                }
            }

            /*sql = "INSERT INTO Chemikalien$(Name, IUPAC Name,Trivialnamen, Summenformel, Sicherheitsdatenblatt, Supplier, Lagerung, Labor, Konsistenz, Anmerkungen) VALUES ('" +
              txt0.Text + "','" + 
              txt1.Text + "','" +
              txt2.Text + "','" +
              txt3.Text + "','" +
              txt4.Text + "','" +
              txt5.Text + "','" + 
              txt6.Text + "','" + 
              txt7.Text + "','" +
              txt8.Text + "','" +
              txt9.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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
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
BeitragVerfasst: 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:
ausblenden 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:
//  quasi-Konstante Werte innerhalb des Formulars, nicht nur in der Methode:
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;
      //  usw. analog, siehe nachstehende Anmerkungen
      //  für numerische Werte wird es etwas komplizierter:
      cmd.Parameters.Add("@PeriodicOrder", OleDbType.Integer).Value 
         = int.Parse( (groupBox2.Controls["txt3"as TextBox).Text );
      //  Befehl ausführen; nur diese beiden Anweisungen benötigen try-catch
      conn.Open();
      cmd.ExecuteNonQuery();
      //  conn.Close() kann entfallen, wird durch using erledigt
   }
}

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 Threadstarter
Hält's aus hier
Beiträge: 8

Win XP
VB, Java, C#
BeitragVerfasst: 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?

ausblenden volle Höhe 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:
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;
               // die Summenformel besteht aus Zahlen und Buchstaben z.B. MgSO4
               // daher habe ich auch dafür VarChar verwendet
               
               // weiterfolgend bis "txt9"

                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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
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
BeitragVerfasst: Mo 29.12.08 17:45 
Hallo Romy,

user profile iconRomy hat folgendes geschrieben Zum zitierten Posting springen:
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!

user profile iconRomy hat folgendes geschrieben Zum zitierten Posting springen:
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:
ausblenden C#-Quelltext
1:
cmdChemErfSp.Click += new EventHandler(SaveNewChemical);					


user profile iconRomy hat folgendes geschrieben Zum zitierten Posting springen:
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:
ausblenden C#-Quelltext
1:
2:
//  gehört zu catch
MessageBox.Show(exp.ToString(), "Fehler beim Speichern");

exp.ToString zeigt erheblich mehr Informationen an als exp.Message.

Gruß Jürgen
Romy Threadstarter
Hält's aus hier
Beiträge: 8

Win XP
VB, Java, C#
BeitragVerfasst: 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.

ausblenden 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";

            //MessageBox.Show(dgv.ColumnCount.ToString());
            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:

ausblenden 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
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
BeitragVerfasst: 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.
ausblenden 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;
//  es ist immer besser, auf die DataTable zuzugreifen statt auf das DGV
foreach(DataColumn col in dt.Columns) {
   //  ColumnName ist schon string
   colnames += " [" + col.ColumnName + "], ";
   colparams += "?, ";
}
//  jetzt alles zusammensetzen
string sql = "INSERT INTO Chemikalien$ (" 
   + colnames.Substring(0, colnames.Length - 2)  //  wegen des Leerzeichens
   + ") VALUES ("
   + colparams.Substring(0, colparams.Length - 2)
   + ");";

//  Befehl erzeugen
OleDbCommand cmd = new OleDbCommand(sql, connection);
//  Parameter hinzufügen
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;
}
//  jetzt Befehl ausführen

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 Threadstarter
Hält's aus hier
Beiträge: 8

Win XP
VB, Java, C#
BeitragVerfasst: 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