Autor |
Beitrag |
glants
      
Beiträge: 20
|
Verfasst: Do 13.08.09 08:55
Hallo !
Da ich in C# als auch beim Posten ein Anfänger bin, entschuldige ich mich schon im Vorhinein für etwaige Verfehlungen. Nun zu meinem Problem. Ich habe ein DataSet aus einer CSV-Datei erstellt und in einem Datagrid angezeigt. Ich möchte nun dieses DataSet in einer vorbereiteten Access-DB speichern. Die Bezeichnungen der Spalten sind gleich. Wie oben erwähnt, bin ich Anfänger. Ich habe mich bereits seit Tagen durch die Foren "gekämpft", bis jetzt ist es mir jedoch nicht gelungen.
Ein Teil des Codes sieht folgendermaßen aus:
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:
| private DataSet GetCVSFile(string pathName, string fileName) { OleDbConnection conn = new OleDbConnection(@"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + pathName + ";Extended Properties=Text;"); OleDbCommand cmd = new OleDbCommand(@"SELECT * FROM " + fileName, conn); da = new OleDbDataAdapter(cmd); OleDbCommandBuilder cb = new OleDbCommandBuilder(da); ds = new DataSet(); da.Fill(ds,"tblTelekom"); dataGridView1.DataSource = ds; dataGridView1.DataMember = "tblTelekom";
DataTable dt = new DataTable(); da.Fill(dt);
foreach (DataRow row in ds.Tables[0].Rows) { row.SetAdded(); }
string connectionstring = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=Telefonie.mdb"; OleDbConnection connDB = new OleDbConnection(connectionstring); OleDbCommand cmdDB = new OleDbCommand(@"SELECT * FROM tblTelekom", connDB); OleDbDataAdapter daDB = new OleDbDataAdapter(cmdDB); OleDbCommandBuilder cbDB = new OleDbCommandBuilder(daDB); DataSet dsDB = new DataSet();
da.Fill(ds, "tblTelekom"); daDB.Update(ds, "tblTelekom"); } |
Ich wäre für jeden weiteren Hinweis dankbar, nur verweist mich bitte nicht irgendwo anders hin, ich war bestimmt schon dort, habe es aber scheinbar nicht verstanden.
Gruß glants
Zuletzt bearbeitet von glants am Sa 15.08.09 16:22, insgesamt 1-mal bearbeitet
|
|
ene
      
Beiträge: 779
Erhaltene Danke: 1
Vista, XP, W2K
Delphi, .Net, Deutsch und Englisch
|
Verfasst: Do 13.08.09 09:05
Moin,
ich würde dir ein anderes Vorgehen vorschlagen: Importiere doch erst die Daten in Access und lasse dir dann die Daten aus der Accesstabelle anzeigen. Das Importieren ist mit folgender Version das einfachste, es setzt allerdings eine formatierte CSV vorraus:
C#-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| string s = "INSERT INTO tbl (abc, xyz) "; s += "SELECT T.abc, T.xyz FROM [EXCEL 8.0;HDR=YES;IMEX=2;DATABASE=C:\\Vorlage.xls].[Tabelle1$] As T "; s += "WHERE T.abc Not In(SELECT abc FROM tbl) ";
OleDbConnection con = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\\db.mdb;User Id=admin;Password=;"); OleDbCommand cmd = new OleDbCommand(s,con); con.Open(); cmd.ExecuteNonQuery();
cmd = null; con.Close(); con = null; |
_________________ Wir, die guten Willens sind, geführt von Ahnungslosen, Versuchen für die Undankbaren das Unmögliche zu vollbringen.
Wir haben soviel mit so wenig so lange versucht, daß wir jetzt qualifiziert sind, fast alles mit Nichts zu bewerkstelligen.
|
|
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 13.08.09 09:21
Hallo glants und
dein Vorgehen ist fast vollständig in Ordnung. Du machst nur den Fehler, beim Speichern ein neues DataSet zu erzeugen und zu füllen. Du willst doch die Daten, die vom CSV aus eingelesen wurden, nach Access übernehmen; also nimm dieses DataSet mit der DataTable tblTelekom für den Update-Befehl - fertig.
Auch im "Lesen"-Abschnitt sind ein überflüssiger new-Befehl, nämlich für eine weitere Tabelle, und ein unsinniges Fill.
Anstelle der SetAdded-Schleife kannst du auch da. AcceptChangesDuringFill auf false setzen; dann erhält jede Zeile automatisch den Status "Eingefügt".
Ergänzend schlage ich vor:
* Setze alles, was eine DbConnection betrifft, in einen using-Block; dann sind die davon betroffenen Ressourcen geschützt und geblockt; die Verbindung wird automatisch aufgelöst.
* Trenne das Einlesen und Speichern in verschiedene Methoden; das macht es übersichtlicher.
Und dringend bitte ich darum, Code als solchen zu kennzeichnen: Text markieren, "Bereiche" aufklappen, C# auswählen, Plus-Button drücken. Das kannst du mit dem Schere-Button auch nachträglich erledigen.
Gruß Jürgen
PS. enes Vorschlag könnte auch bei CSV funktionieren, auch wenn er es mit Excel gemacht hat. Welcher Weg besser ist, hängt vom gesamten Vorgehen ab.
|
|
ene
      
Beiträge: 779
Erhaltene Danke: 1
Vista, XP, W2K
Delphi, .Net, Deutsch und Englisch
|
Verfasst: Do 13.08.09 10:20
Alternative, wenn man mit einer CSV arbeiten will (die Excelversion hat mit CSV Vorteile):
Quelltext 1:
| FROM [Text;DSN=Spezifikation;FMT=Delimited;HDR=yes;IMEX=2;CharacterSet=850;DATABASE=C:\].Datei.csv; |
_________________ Wir, die guten Willens sind, geführt von Ahnungslosen, Versuchen für die Undankbaren das Unmögliche zu vollbringen.
Wir haben soviel mit so wenig so lange versucht, daß wir jetzt qualifiziert sind, fast alles mit Nichts zu bewerkstelligen.
|
|
glants 
      
Beiträge: 20
|
Verfasst: Fr 14.08.09 21:30
Hallo !
Vielen Dank für die Antworten. Es war mir nicht möglich mich vorher zu bedanken. Nehme Eure Anregungen gerne auf - auch hinsichtlich Etikette.
mfg
glants
|
|
glants 
      
Beiträge: 20
|
Verfasst: Fr 14.08.09 21:54
Hallo JüTho !
"...also nimm dieses DataSet mit der DataTable tblTelekom für den Update-Befehl - fertig ..." - ich habe versucht dies irgendwie auf die Reihe zu bekommen, aber wie oben erwähnt, ich bin Rooky. Ich dachte eigentlich, dass ich genau das mittels "daDB.Update(ds, "tblTelekom"); " mache. Kannst du das präzisieren ? Ich bin schon "etwas" verzweifelt !
mfg
glants
Zuletzt bearbeitet von glants am Sa 15.08.09 17:11, 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: Sa 15.08.09 12:00
Tatsächlich, durch die überflüssigen new- und Fill-Befehle bin ich auch verwirrt worden. Es sieht richtig aus.
Lass dir nach dem CommandBuilder mal daDB.InsertCommand anzeigen (durch Debugger oder Console.WriteLine oder MessageBox): Was steht da drin? Sind die Spaltennamen der csv- und Access-Tabellen wirklich identisch?
Jürgen
PS.
Zitat: | Und dringend bitte ich darum, Code als solchen zu kennzeichnen: Text markieren, "Bereiche" aufklappen, C# auswählen, Plus-Button drücken. Das kannst du mit dem Schere-Button auch nachträglich erledigen. |
Das kannst du auch jetzt noch machen!
|
|
glants 
      
Beiträge: 20
|
Verfasst: Sa 15.08.09 18:12
Hallo Jürgen !
Danke für deine Bemühung. Ich habe den Code etwas umgebaut
C#-Quelltext 1: 2: 3: 4: 5: 6: 7:
| DataSet dsDB = new DataSet(); da.Fill(dsDB, "tblTelekom"); dataGridView2.DataSource = dsDB; dataGridView2.DataMember = "tblTelekom"; daDB.Update(dsDB); return ds; |
und gesehen, dass die Daten des ersten, im zweiten Grid angezeigt werden. In der vorletzten Zeile (daDB.Update(dsDB)) bekomme ich jedoch folgende Fehlermeldung: "...Aktualisieren: TableMapping['Table'] oder DataTable 'Table' kann nicht gefunden werden. ...". Im Zuge meiner Experimente bin ich schön mal darüber gestolpert. Nachzulesen war, dass in der Tabelle der Primärschlüssel fehlt. Habe einen hinzugefügt, aber es funktioniert trotzdem nicht. Was läuft da falsch und was kann ich dagegen machen ?
mfg
glants
|
|
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: Sa 15.08.09 18:59
glants hat folgendes geschrieben : | Nachzulesen war, dass in der Tabelle der Primärschlüssel fehlt. Habe einen hinzugefügt, aber es funktioniert trotzdem nicht. |
Hast du ihn auch im DataSet eingefügt? Siehe in der SDK-Doku die UniqueConstraint-Klasse.
Hintergrund: Der CommandBuilder kann nur dann die SQL-Befehle automatisch erstellen, wenn die Spalten des PrimaryKey im SELECT-Befehl enthalten sind (das ist bei "Select * " zwangsläufig erfüllt) und der PK in der DataTable definiert ist; das scheint noch zu fehlen.
Alternative: Du verzichtest auf den CommandBuilder und setzt die SQL-Befehle (vor allem den InsertCommand) manuell per Code.
Gruß Jürgen
|
|
glants 
      
Beiträge: 20
|
Verfasst: So 16.08.09 17:43
Hallo Jürgen !
Ich habe nun im DataGrid eine Spalte "ID", aber nicht explizit als Primarykey. Dier Spalte habe ich über die "Schema.ini" angelegt, weil ich die csv-Datei sonst nicht vernünftig einlesen konnte. Angeblich soll ja auch entweder im DataSet oder in der Datenbank der PK (autowert) eingetragen werden. Die Fehlermeldung beim "update"-Befehl ist die gleiche:
Zitat: | System.Data.OleDb.OleDbException wurde nicht behandelt.
Message="Syntaxfehler in der INSERT INTO-Anweisung."
Source="Microsoft JET Database Engine"
ErrorCode=-2147217900
StackTrace:.... |
Was kann ich noch tun - ich weiß, ich bin ein schwerer Fall !
mfg
Glants
|
|
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: So 16.08.09 18:26
Und was ist mit dieser Frage:
JüTho hat folgendes geschrieben : | Lass dir nach dem CommandBuilder mal daDB.InsertCommand anzeigen (durch Debugger oder Console.WriteLine oder MessageBox): Was steht da drin? |
Die Fehlermeldung deutet darauf hin, dass es in diesem Zusammenhang Probleme gibt. Ich könnte mir vorstellen, dass Zahlen und/oder Datumsangaben nicht korrekt eingelesen und übertragen werden.
Wichtig ist auch, dass Parameter benutzt werden (natürlich korrekt). Mehr Informationen darüber findest du unter [Artikelserie] Parameter von SQL Befehlen; ich warne dich aber: Das ist zwar von Anfang an äußerst wichtig, aber eher Wissen für Fortgeschrittene.
Gruß Jürgen
|
|
glants 
      
Beiträge: 20
|
Verfasst: So 16.08.09 21:47
Hallo Jürgen !
Habe mich bemüht mit "..daDB.InsertCommand anzeigen (durch Debugger oder Console.WriteLine oder MessageBox.." etwas anzufangen, bin damit aber, so glaube ich, nicht zusammengekommen. Was soll da drin stehen ? Beim Debuggen stoße ich dann irgendwo auf den String "SELECT * FROM tblTelekom" ! Meinst du das ? Ich MUSS es schaffen die in das DataSet eingelesene csv-Datei in das Access zu bringen. Habe die Datei eingelesen, zerstückelt und wieder hinaus geschrieben - es fehlt nur mehr die Sch... Speicherung im Access. Ich bitte nochmals um Hilfe. Die Schema.ini hab' ich zur Ansicht angehängt.
mfg
Glants
Einloggen, um Attachments anzusehen!
|
|
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 17.08.09 08:26
glants hat folgendes geschrieben : | Habe mich bemüht mit "..daDB.InsertCommand anzeigen (durch Debugger oder Console.WriteLine oder MessageBox.." etwas anzufangen, bin damit aber, so glaube ich, nicht zusammengekommen. Was soll da drin stehen ? |
Na, etwas wie "INSERT INTO..." Aber ich war nicht genau genug; dazu ist die SDK-Doku/MSDN da, dass du auch selbst solche Fehler feststellst und korrigierst: daDB.InsertCommand ist vom Typ DbCommand und nicht vom Typ String; also muss noch eine passende Eigenschaft dieses DbCommand gelesen werden, und das ist sinnvollerweise CommandText. Wenn dieser leer ist, dann konnte der CommandBuilder nicht erfolgreich arbeiten.
glants hat folgendes geschrieben : | Beim Debuggen stoße ich dann irgendwo auf den String "SELECT * FROM tblTelekom" ! Meinst du das ? |
Natürlich nicht; ich wollte einen Insert-Befehl sehen und keinen Select-Befehl. Schau genau hin, das steht höchstwahrscheinlich in daDB.SelectCommand.CommandText.
Du kannst das Ergebnis des CommandBuilders auch noch durch den String DbCommandBuilder.GetInsertCommand.CommandText anzeigen lassen.
glants hat folgendes geschrieben : | Die Schema.ini hab' ich zur Ansicht angehängt. |
Die hilft nur zusammen mit den anderen Angaben: Tabellenstruktur in Access, Insert-Befehl.
Gruß Jürgen
|
|
glants 
      
Beiträge: 20
|
Verfasst: Mo 17.08.09 23:40
Hallo Jürgen !
Ich bedanke mich nochmals für die Hilfe und deine Ausdauer. Ich bring das DataGrid einfach nicht in das Access. Dehalb habe ich nun versucht meine ersten Gedanken umzusetzen und die erzeugte csv-Datei direkt nach Access zu schreiben. Ich werde mich auch weiter mit allem auseinandersetzen. Leider läuft mir die Zeit davon !!! Deshalb meine konkrete Frage: kannst du mir Code zur Verfügung stellen, mit dem es möglich ist die Datei im Anhang in das Access zu bringen ?? Muss natürlich nicht umsonst sein.....
mfg
Glants
Einloggen, um Attachments anzusehen!
|
|
ene
      
Beiträge: 779
Erhaltene Danke: 1
Vista, XP, W2K
Delphi, .Net, Deutsch und Englisch
|
Verfasst: Di 18.08.09 07:09
Was spricht dabei gegen meinen Vorschlag die Datei direkt in die Accesstabelle anzufügen? Mit der zweiten Abfragesyntax kann ich deine Textdatei direkt in Access verwenden, also kann man sie auch auf dem Wege gleich an eine Tabelle anfügen und dein Grid muss nichts weiter können, als die Accesstabelle zu verarbeiten.
_________________ Wir, die guten Willens sind, geführt von Ahnungslosen, Versuchen für die Undankbaren das Unmögliche zu vollbringen.
Wir haben soviel mit so wenig so lange versucht, daß wir jetzt qualifiziert sind, fast alles mit Nichts zu bewerkstelligen.
|
|
glants 
      
Beiträge: 20
|
Verfasst: Di 18.08.09 16:41
Hallo Jan !
Danke für's "einklinken" ! Gegen deine Idee spricht natürlich gar nichts. Ich habe mich leider irgendwie in das DataSet "verannt" und alle anderen Möglichkeiten nicht mehr beachtet. Im darüber stehenden Beitrag habe ich die csv-Datei angehängt welche in das Access soll. Geht das auch, ohne den Umweg einer Excel Datei ?
mfg
gernot
|
|
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 18.08.09 18:09
Genau lesen hilft ungemein; das hat er doch am Do 13.08.09 10:20 Uhr schon erläutert. Jürgen
|
|
glants 
      
Beiträge: 20
|
Verfasst: Di 18.08.09 22:00
Ich habe den sql-String mittels StringBuilder erstellt, weil es mir übersichtlicher erscheint (habe zuvor in Jans's Version begonnen). Nach dem Hinweis, dass es einige "ungültige Argumente" in der OleDBCommand-Zeile und "Argument: kann nicht von "System.Text.StringBuilder" in "string" konvertiert werden" in der gleichen Zeile habe ich das ".ToString" angehängt. Nun läuft es zwar durch, aber in das Access wird nichts geschrieben. Ich kann für mich beim Debuggen keine Fehler mehr erkennen. Ich erbitte nochmals um Hilfe bzw. um Unterstützung.
mfg
gernot
C#-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22:
| StringBuilder insSql = new StringBuilder(); insSql = insSql.Append("INSERT INTO tblTelekom (ID, Anschluss, Rufnummer, Ziel, Zone, "); insSql = insSql.Append("Datum, Verbindungszeit, Anfang, Dauer, TE, Tarif, Betrag, Waehrung) "); insSql = insSql.Append("Select T.ID, T.Anschluss, T.Rufnummer, T.Ziel, T.Zone, "); insSql = insSql.Append("T.Datum, T.Verbindungszeit, T.Anfang, T.Dauer, T.TE, T.Tarif, T.Betrag, T.Waehrung "); insSql = insSql.Append("FROM [Text;DSN=Spezifikation;FMT=CustomDelimited(;);HDR=yes;IMEX=2;CharacterSet=850;DATABASE="); insSql = insSql.Append(pathName); insSql = insSql.Append("]."); insSql = insSql.Append(fileName); insSql = insSql.Append(" AS T WHERE T.ID Not In(Select ID FROM tblTelekom) "); string connectionstring = @"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=Telefonie.mdb;User Id=admin;Password=;"; OleDbConnection connDB = new OleDbConnection(connectionstring); OleDbCommand cmdDB = new OleDbCommand(insSql.ToString(), connDB); connDB.Open(); cmdDB = null; connDB.Close(); connDB = null; |
|
|
glants 
      
Beiträge: 20
|
Verfasst: Di 18.08.09 23:13
Zusätzlich habe ich nun noch mal alle Varianten mit nur 2 Tabellenspalten durchprobiert (Delimited (  , Pfade zu den Dateien geändert, etc). - alles was mir eingefallen ist. Doch leider tut sich in der DB wieder überhaupt nichts, auch Fehlermeldung kommt keine. Ich bitte nochmals ganz dringend (ich hoffe das letzte mal) um eure Hilfe !!!!
mfg
Glants
|
|
ene
      
Beiträge: 779
Erhaltene Danke: 1
Vista, XP, W2K
Delphi, .Net, Deutsch und Englisch
|
Verfasst: Mi 19.08.09 07:13
Also...
1) Ich hatte gestern deine Datei direkt mit der Abfrage in Access angefügt:
Quelltext 1:
| FROM [Text;;FMT=Delimited;HDR=yes;IMEX=2;CharacterSet=850;DATABASE=C:\].Datei.csv; |
DSN kannst du weglassen, wenn du keine Importspezifikation hast.
2) Wenn ID ein Autowert in Access ist, kannst du diesen nicht anfügen und in deiner Datei ist er eh null.
3) Pathname und Filename sind richtig?
4) Du öffnest eine Connection, übergibst ein Command der Connection und schließt dann alles wieder...merkste watt? Da fehlt ein cmdDB.ExecuteNonQuery(); Wie in meinem ersten Beitrag zu sehen.
_________________ Wir, die guten Willens sind, geführt von Ahnungslosen, Versuchen für die Undankbaren das Unmögliche zu vollbringen.
Wir haben soviel mit so wenig so lange versucht, daß wir jetzt qualifiziert sind, fast alles mit Nichts zu bewerkstelligen.
|
|
|