Laden...

Forenbeiträge von juetho Ingesamt 3.331 Beiträge

05.08.2009 - 11:56 Uhr

Hallo,

ich vermisse das Füllen der DataRow mit Werten. Vor allem fehlt aber das Hinzufügen der neuen DataRow zur RowsCollection der DataTable:

//  erzeuge die DataRow
SaveLineRow = (DSLines_ALL.DTLines_ALLRow)SaveLineTable.NewRow();
//  weise den Spalten Werte zu
SaveLineRow["ID"] = 17;
SaveLineRow["Name"] = "was auch immer";
//  registriere die DataRow als Teil der DataTable
SaveLineTable.Rows.Add(SaveLineRow);

Genauso steht es auch im Beispiel unter :rtfm: DataRow-Klasse; das wäre also auch ein Fall für Wie poste ich richtig? Punkt 1.1 Erst in die Doku schauen

Gruß Jürgen

05.08.2009 - 09:45 Uhr

@RobS
Nein, das ist nicht korrekt. Der EventHandler gilt bei deinem Vorgehen automatisch für alle Zellen des DGV, die eine TextBox benutzen (nämlich immer dieselbe TextBox). Wenn du auch nur eine Spalte hast, die normale Texteingaben erlauben sollte, verhinderst du dies mit diesem EventHandler. Es geht nicht um irgendwelche TextBoxen auf einem Formular, sondern immer nur um die eine im DGV.

Also berücksichtige diese Hinweise:

Wenn dieser EventHandler nur für einzelne Spalten und nicht für alle benötigt wird, darfst du nicht vergessen, ihn beim Verlassen des Feldes auch wieder abzuhängen.

Muß das .EditingControl.KeyDown - Event nicht iwann mal wieder deregistriert werden?

Jürgen

04.08.2009 - 09:31 Uhr

@ErfinderDesRades

Zwischenzeitlich habe ich die Lösung gefunden.
Ich muss per NotifyCurrentCellDirty dem DataGridView mitteilen, dass sich die Zelle geändert hat.

@Rocket
Auch wenn dein Ansatz nicht mit DataTable zusammengeht, ist es dennoch weit besser, die Daten gleich welcher Struktur von der GUI zu trennen. Mach eine Klasse, die nur den Bedingungen deiner Schnittstelle entspricht, und verbinde diese mit den jeweiligen Controls. Sonst kommst du immer wieder zu ähnlichen Problemen wie hier beim DGV.

Jürgen

04.08.2009 - 09:26 Uhr

Hallo,

das Problem liegt darin, dass das DGV insgesamt (!) genau eine TextBox kennt. Diese wird durch EditingControlShowing aktiviert und an der richtigen Stelle angezeigt.

Du kannst einen "externen" EventHandler für KeyDown oder KeyPress erstellen (je nachdem, was für deine Zwecke besser geeignet ist - siehe auch [FAQ] In einer TextBox nur bestimmte Zeichen/Eingaben zulassen) und diesen beim ersten Aufruf von EditingControlShowing an (e.Control as TextBox) hängen. Wenn dieser EventHandler nur für einzelne Spalten und nicht für alle benötigt wird, darfst du nicht vergessen, ihn beim Verlassen des Feldes auch wieder abzuhängen.

Zum weiteren Verständnis siehe auch MaskedTextBox in einer DataGridViewColumn oder verkürzt DataGridViewTextBox: automatisch ToUpper

Gruß Jürgen

04.08.2009 - 09:14 Uhr

... bekomme ich Fehlermeldungen. Irgendwie ist das Steuerelement adsBool nicht so recht in meinem Projekt bekannt.

Ein UserControl ist eine eigene Klasse, also üblicherweise in einer eigenen Quelldatei enthalten. Ist die Referenz vorhanden (sofern es in einer eigenen Assembly steckt)? Hast du den **Namespace **per using hinzugefügt?

Übrigens ist in so einer Situation eine List<adsBool> besser als ein Array, weil es flexibler ist. Und Klassennamen (also auch UserControls) sollten mit einem Großbuchstaben anfangen.

Gruß Jürgen

PS. Zur ursprünglichen Frage möchte ich noch auf [FAQ] Variablennamen zur Laufzeit zusammensetzen verweisen. Das solltest du zumindest wegen des besseren Verständnisses noch durchlesen; es könnte dir auch sonst beim weiteren Vorgehen helfen

03.08.2009 - 17:00 Uhr

Die Anleitung hast du doch schon längst bekommen:

du kannst den text

Du musst also mit myTextBox.Text arbeiten, das ist ein String.

zeichen für zeichen durchgehen

Ein String enthält Chars als Liste der Zeichen. "Zeichen für Zeichen" heißt also: benutze eine Schleife (for oder foreach) für alle Zeichen von Anfang bis Ende.

und zB mit char.IsNumeric(char) prüfen, ob es eine zahl ist.

Wo kann es bei der Umsetzung dieser Anleitung in konkreten Code ein Problem geben?

Was jetzt noch fehlen könnte, ist in den Beispielen von :rtfm: zu finden.

Auch deine Fragen im Entwickler-Forum lassen mich daran zweifeln, dass du dir die Grundlagen aneignen willst.

Jürgen

PS. Was hat das eigentlich mit "Datentechnologien" zu tun? Das sind Grundlagen, also Basistechnologien. Die Fragestellung bezieht sich auf "Textbox", die Überschrift auf "Textdatei". Was denn nun? Bitte erst nachdenken, dann suchen, dann selbst versuchen, erst dann fragen!

03.08.2009 - 09:37 Uhr

Was muss ich noch machen um die neue Zeile per Code zu erzeugen?

Das DataGridView dient, wie der Name schon sagt, dazu, Daten in einem Grid zur Anzeige (oder Bearbeitung) zu bringen. Vorzugsweise ist deshalb per Code nicht das DGV zu bearbeiten, sondern die dahinterliegende Datenmenge. Benutze und bearbeite diese (z.B. eine DataTable), dann wirst du viele Probleme vermeiden.

Jürgen

02.08.2009 - 14:37 Uhr

Ich bekenne mich "schuldig": In der Delphi-Praxis gab es genau die gleiche Frage; also habe ich auf deine Lösung hingewiesen. Der Fragesteller konnte mit C# nichts anfangen, und mein Delphi ist eingerostet. Aber die DP ist so aktiv, dass daraus schnell eine komplette Lösung wurde. Die habe ich heute wenigstens erläutert. Jürgen

31.07.2009 - 13:44 Uhr

Hallo Jürgen 😉

ich empfehle dringend, nicht Odbc zu verwenden, sondern den SqlClient, der ist schließlich für MS-SQL gedacht. Mit Oledb und erst Odbc gibt es immer wieder Probleme, für die keine Erklärung gefunden wird; mit dem "richtigen" SqlProvider klappt es dann.

Gruß Jürgen

31.07.2009 - 09:34 Uhr

Der Vollständigkeit halber möchte ich noch auf [FAQ] Tabellen- und Spalteninformationen aus dem SQL Server auslesen verweisen.

Siehe auch Wie poste ich richtig? 1.1 Erst suchen, vor allem in den FAQ

Die Exception lautet : Ungültiger Spaltenname [table], da ist nur ne kleiner Fehler drin,...

In allen Beispielen wird der Tabellenname in Hochkommata gesetzt; dies ist wichtig, weil es sich um einen String handelt, und bei dir fehlt es. Damit das nicht zu einem Problem führt, solltest du Khalids Hinweis mit den Parametern unbedingt beachten.

aber ich habe noch kaum Erfahrung C# SQL Anweisungen durchzuführen

Deshalb verweise ich auch auf [FAQ] SQL - Kurze Befehlzusammenfassung

Jürgen

30.07.2009 - 11:18 Uhr

Hallo und willkommen,

sowohl bei **Parse **als auch bei **TryParse **gibt es Überladungen, in denen du einen **FormatProvider **(und NumberStyles) angeben kannst. Auch deshalb lohnt sich ein Blick in :rtfm:

Gruß Jürgen

Gü war schneller, aber wegen meines generellen Hinweises schicke ich meine Antwort trotzdem ab.

28.07.2009 - 16:56 Uhr

Hallo und willkommen,

ich habe kürzlich etwas Ähnliches gemacht und **Bedingungsfelder **mit anderen Feldinhalten verknüpft:

{ IF { MERGEFIELD Signatur1 } = "Hugo" "{ MERGEFIELD Vorname } grüßt Hugo" "" }

Ob das auch mit solchen Include-Anweisungen klappt, wäre auszuprobieren.

Bitte nicht meckern, dass anstelle des festen Textes "Hugo" das Feld benutzt werden könnte; der konkrete Text unterschied sich in meinem Fall.

Gruß Jürgen

28.07.2009 - 16:42 Uhr

Noch ein paar Hinweise.

Ps.: Die Connection "conn" ist als globales Object definiert.

Das gehört auch zu den Verfahren, die unbedingt vermieden werden sollen. An Khalids Struktur siehst du, dass das nur in einen Teil, nämlich den DAL, hineingehört. Siehe auch [Artikel] Ressourcen schonen - Datenbanken richtig öffnen und schließen

Bei Oledb werden Parameter mit '?' gekennzeichnet, dein AddToDo-Code müsste also zumindest so geändert werden:

StringBuilder sb = new StringBuilder();
sb.AppendLine("INSERT INTO ToDo_List ([Priorität], [Beschreibung], [Anfangsdatum], [Enddatum], [Erstelldatum])");
sb.AppendLine("VALUES (?, ?, ?, ?, ?)");
// ...
cmd.Parameters.AddWithValue("Priorität", prioritaet ?? Convert.DBNull);

Siehe auch Parameter von SQL Befehlen - Unterschiede der DbProvider

Ich bezweifle auch, dass die Parameter bei dir richtig erkannt werden, z.B. bei dieser Zeile:

cmd.Parameters.AddWithValue("Erstelldatum", DateTime.Now.ToShortDateString());

Das übergibt das heutige Datum als String. Damit kann das Access-Datum aber nur "per Zufall" etwas anfangen. Wenn du die Uhrzeit übergehen willst, dann mach es doch so:

cmd.Parameters.AddWithValue("Erstelldatum", DateTime.Now.Date);

Auch das ständige Konvertieren (ToString, dann ToDateTime, dann wieder ToString) sieht eher abwegig aus. Wenn der Wert als Datum kommt, dann verarbeite es doch auch so. Beispiel:

//  nicht so:
DateTime anf_dt = Convert.ToDateTime(dr[3].ToString());
string anf_datum_item = anf_dt.ToShortDateString();
string[] add_item = new string[] { Row.ToString(), prio_item, beschreibung_item, anf_datum_item, end_datum_item };

//  sondern so, vorausgesetzt, in dr[3] ist ein DateTime:
DateTime anf_dt = (DateTime)dr[3];
string[] add_item = new string[] { Row.ToString(), prio_item, beschreibung_item, anf_dt.ToShortDateString, end_datum_item };

Aber das dürfte sich durch eine bessere Datenstruktur sowieso einfacher regeln.

Gruß Jürgen

28.07.2009 - 09:09 Uhr

Hallo,

mir kommt dein ganzes Vorgehen etwas seltsam vor. Über einen DataReader Werte (!) einzulesen und daraus einen Insert-Befehl zu konstruieren (wenn auch grundsätzlich korrekt mit Parametern), kommt mir sehr umständlich vor. Fehler treten wahrscheinlich dadurch auf, dass bei Parameters.AddWithValue nur ein Typ "object" übergeben wird. Was passiert, wenn es sich dabei um einen null-Wert oder eine ganze Zahl handelt?

Vorschlag: Benutze einen der korrekten Wege, um die Datenstruktur abzuholen, nämlich DbDataReader.GetSchemaTable oder DbSqlConnection.GetSchema und eine der Varianten von Parameters.Add.

Jürgen

20.07.2009 - 09:41 Uhr

Versuche einmal TOP 1 (oder LIMIT oder wie auch immer es bei MS-SQL heißt) i.V.m. GROUP BY.

Übrigens ist OleDb bei MS-SQL ziemlich daneben, dafür gibt es den SqlClient.

Jürgen

16.07.2009 - 08:39 Uhr

Hallo,

mir geht es ähnlich wie blackcoin: Auch ich verstehe nicht, was für Änderungen du wo machen willst.

Du hast aber offensichtlich ein Grundproblem beim Verständnis: Das DataGridView ist (wie schon der Name sagt), dazu gedacht, Daten in einem Grid anzuzeigen. Wichtig ist dabei, dass es sich um eine Datenmenge handelt, die den "üblichen" Voraussetzungen entspricht, wie die Hinweise in :rtfm: DataGridView.DataSource feststellen:

Normalerweise erfolgt die Bindung an eine BindingSource-Komponente und die Bindung der BindingSource-Komponente an eine andere Datenquelle, oder sie wird mit Geschäftsobjekten aufgefüllt. Die BindingSource-Komponente ist die bevorzugte Datenquelle, weil sie an eine Vielzahl unterschiedlicher Datenquellen gebunden werden kann und viele Datenbindungsprobleme automatisch beheben kann.

Meine dringende Empfehlung lautet: Verabschiede dich von dem Gedanken, dass du das DataGridView bearbeitest, sondern befasse dich mit einer passenden Datenstruktur. Das würde auch besser zur NET-Philosophie und OOP passen, in denen GUI und Daten getrennt werden.

Jürgen

15.07.2009 - 17:42 Uhr

@FZelle
Das ist mir schon klar, aber ich hatte wenigstens gehofft...

Danke Rainbird, so ähnlich (wenn auch nicht ganz so ausführlich) hatte ich mir das gedacht.

Wenn es jetzt noch eine weitere Empfehlung gibt, dann könnte man das zusammenstellen.

Jürgen

15.07.2009 - 15:46 Uhr

(Komisch: Wenn jemand konkret nach solchen Empfehlungen fragt, bekommt er ruck-zuck mehrere Antworten, und zwar bekommt jeder neue Fragesteller dieselben Antworten. Wenn ich diese Empfehlungen einmal für alle zusammenstellen möchte, haltet ihr euch zurück. Will denn niemand etwas für MS-SQL Server Express oder für MySql oder SQLite oder ... sagen und begründen? ? Jürgen

15.07.2009 - 15:39 Uhr

Grundsätzlich nein. Über die Forumssuche nach datagridview zellen verbinden gibt es Hinweise.

Jürgen

15.07.2009 - 15:06 Uhr

SelectedRows.CopyTo() ist auch überflüssig, weil SelectedRows bereits ein Array ist. So geht es direkt:

DataGridViewRow[] dgvr = dataGridView1.SelectedRows;  

Jürgen
Das hatte ich zuerst auch gedacht, dataGridView1.SelectedRows ist allerdings eine Collection und kein Array, deswegen das CopyTo().

Du hast ja recht; meine Arbeitsanleitung in meinem ersten Beitrag hat das ja ganz genau so beschrieben. Ich hatte mich durch die (z.T. überflüssigen) Variablen dazwischen irritieren lassen.

Denn es geht auch kürzer:

DataGridViewSelectedRowCollection items = dataGridView1.SelectedRows;
foreach(DataGridViewRow item in items) {
  DataRowView row = item.DataBoundItem as DataRowView;
  pdt.ImportRow(row.Row);
}

Ob foreach in dieser Form klappt, bin ich mir nicht sicher; aber mit einer for-Schleife und Zugriff auf items[x1] würde es sicher gehen.

Ich hoffe, dass ich mich nicht irgendwo verschrieben habe; durch die vielen Row und View kann man schon durcheinander kommen.

Jürgen

15.07.2009 - 14:28 Uhr

Hallo,

das Problem liegt darin, dass es für das gesamte DataGridView (für alle Spalten!) genau einen Button gibt, der nur bei Bedarf (nämlich bei BeginEnter) an der betreffenden Stelle eingeblendet wird. Durch DataGridView.EditingControlShowing kommst du dann an diesen Button und kannst ihn bearbeiten.

Eine Idee, wie du stattdessen vorgehen kannst, habe ich allerdings nicht.

Jürgen

15.07.2009 - 13:52 Uhr

Dein Vorschlag mit ImportRow klappt irgendwie nicht:

pdt.ImportRow(dgvr[i].DataBoundItem);  

Er erwartet unbedingt eine Datarow, aber mit Databounditem bekomme ich nur ein Datarowview.

Sorry, da habe ich in der Erinnerung einen Schritt vergessen. Du hast soweit recht, aber mit DataRowView.Row bekommst du die benötigte DataRow.

Die Zusammenarbeit zwischen der temp. DataTable und der globalen pdt kommt mir zumindest seltsam vor (ich wollte es als Quatsch bezeichnen, aber da ich nicht weiß, was für Gedanken du dir "außerhalb" gemacht hast, formuliere ich es nicht so). Eigentlich sollten diese Schritte genügen (sofern FillSchema überhaupt nötig ist):

           DataTable table = new DataTable();

           adapter.SelectCommand = command;
           adapter.FillSchema(table, SchemaType.Mapped);
           adapter.Fill(table);

           return table;

SelectedRows.CopyTo() ist auch überflüssig, weil SelectedRows bereits ein Array ist. So geht es direkt:

DataGridViewRow[] dgvr = dataGridView1.SelectedRows;

In diesem Zusammenhang macht sich wahrscheinlich die mehrfache Verwendung der pdt negativ bemerkbar. Vorschlag: Benutze ein DataSet mit einer Haupttabelle und einer temporären Zusatztabelle, die per Clone erzeugt wurde und manuell die Kopien aufnimmt.

Jürgen

15.07.2009 - 09:12 Uhr

Hallo Micha und willkommen,

und bin kläglich gescheitert

Auch dann wäre es hilfreich zu erfahren, was genau du versucht hast.

Es ist aber in der Tat etwas komplizierter, weil das DGV zur Anzeige einer Datenmenge gedacht ist und sich die Auswahl einer oder mehrerer Zeilen nicht unmittelbar auf die dahinterliegende DataTable überträgt.

Du kannst schrittweise so vorgehen:*Mit DGV.SelectedRows bekommst due ausgewählten Zeilen. *Mit CopyTo kannst du diese in ein DataGridViewRow-Array übertragen. *Jede einzelne Zeile darin kann durch DataBoundItem in eine DataRow konvertiert werden. *Durch DataTable.Clone bekommst du eine leere Kopie der DataTable. *Dort kannst du die einzelnen DataRows einfügen. (Eventuell muss das über den Umweg von ImportRow geschehen, weil eine DataRow nicht in zwei DataTables enthalten sein kann.) *Dann kannst du diese DataTable mit WriteXml separat speichern.

Ich glaube nicht, dass es einen wesentlich einfacheren Weg gibt. In vielen Fällen hilft es, eine BindingSource dazwischenzuschalten; aber auch diese kennt nur eine einzige Current, aber nicht mehrere SelectedXxx.

Zur Frage des Unterforums: DGV und DataTable liefern Zweifelsfälle. Dein Problem tritt im Bereich DGV auf, gehört also zu WinForms. Die Lösung muss über DataTable gehen, gehört also zu Datentechnologien. Also würfeln wir...

Gruß Jürgen

13.07.2009 - 15:11 Uhr

... und diese Art, einen SELECT-String zusammenzubasteln, ist ziemlich miserabel. Das richtige Verfahren ist unter [Artikelserie] Parameter von SQL Befehlen erläutert. Jürgen

12.07.2009 - 10:55 Uhr

Habe ich das richtig verstanden, dass du deine typed Datasets selber codest?

Mir ist zwar nicht klar, wonach du das vermutest; Bernd schreibt ein typ.DS mit Sicherheit nicht selbst - ich habe schon Datenmonster mit 1 MB in mehreren 1000 Zeilen gesehen. Es geht aber ziemlich einfach über :rtfm: xsd.exe - das dafür benötigte xsd-Schema kann man auch manuell erstellen. Jürgen

12.07.2009 - 10:48 Uhr

Ein solches Problem führt zu :rtfm: Bei allen genannten Methoden gibt es Überladungen, bei denen ein **IFormatProvider **angegeben werden kann, vor allem bei double.(Try)Parse zusätzlich NumberStyles.

Jürgen

10.07.2009 - 16:30 Uhr

Firebird ist eine freie Open-Source-Datenbank, die von einer sehr aktiven Gemeinde entwickelt wird. Die Installationsroutine ist zu finden über Sourceforge.net. Das Programm muss installiert werden ("read the guide"), aber die Installation verläuft eigentlich immer problemlos.

Darin enthalten sind auch verschiedene Hilfsprogramme für die DB-Administration. Stattdessen stehen auch IBExpert (Personal) oder FlameRobin zur Verfügung.

Die Lizenzbedingungen stehen unter Firebird - Initial Developer's PUBLIC LICENSE.

Die embedded-Version von Firebird kann jederzeit durch die Server-Version ersetzt werden. Es ist unter Umständen auch möglich, mehrere FB-Versionen parallel zu betreiben.

Für ADO.NET steht der Firebird .NET Data Provider mit dem FirebirdSql.Data.FirebirdClient-Namespace zur Verfügung. Für Programmierer, die mit Visual Studio entwickeln, wird zusätzlich der DDEX Provider benötigt; in den VS-Express-Versionen kann der Datenbank-Designer nicht mit Firebird zusammenarbeiten.

Jürgen

10.07.2009 - 16:28 Uhr

Immer wieder kommt die Frage: Welche Datenbank? Ich möchte mit dieser Diskussion eine Zusammenstellung erreichen, die dann als FAQ oder Artikel veröffentlicht werden soll.

Problemstellung
Für ein Programm wird eine "richtige" SQL-Datenbank gesucht. Die Datenbank soll nur lokal, also auch ohne Zugriff durch mehrere Benutzer arbeiten. Die Installation sowohl des Datenbank-Programms als auch des NET Data Provider soll einfach sein und sich auf das Kopieren von einer oder einigen wenigen DLLs beschränken. Es wäre gut, wenn das DBMS später durch einen SQL-Server für mehrere Benutzer ersetzt werden kann, ohne dass dafür großer Aufwand nötig wird.

Lösung
Jeder, der ein solches Datenbank-System empfiehlt, möge bitte in seinem Beitrag folgende Punkte erwähnen (ähnlich wie ich in meinem Firebird-Vorschlag):*Name des Datenbank-Systems und Link für den Download *Begründung für die Empfehlung (soweit sinnvoll) *Hinweis auf ein Administrationsprogramm *Hinweis (Link) auf Lizenzbedingungen für die (vorzugsweise freie) Benutzung der DB *Verweis auf einen passenden "großen" Server *Name des NET Data Provider und Link für den Download

Wenn einige sinnvolle Empfehlungen gekommen sind, möchte ich diese Beiträge als FAQ oder Artikel zusammenstellen und den Power-Usern zur Veröffentlichung empfehlen. Danke für die Mitarbeit bei dieser Gemeinschaftsaktion!

Jürgen

10.07.2009 - 11:47 Uhr

Florians Verdacht teile ich.

byob hat implizit darauf hingewiesen, dass Trim einen String zurückliefert.

Für C#-Code gibt es den schönen #-Button; das liest sich besser als Kursivtext. Nach 4½ Jahren und 172 Beiträgen solltest du das schonmal mitbekommen haben.

Jürgen

10.07.2009 - 11:12 Uhr

Hmm, eine explizite Option RequirePrimaryKey kenne ich auch nicht.

Hbae auch schon gesucht wo ich die option "RequirePrimaryKey" angewählt haben soll, finde aber nichts 😦

Also meine Frage jetzt, wo und wie muss ich den primary key angeben oder wie ich die oben genannte option ausstellen kann.

Normalerweise weist diese Fehlermeldung darauf hin, dass der CommandBuilder im SelectCommand das Feld (bzw. die Felder) erwartet, die den PrimaryKey bilden. Üblicherweise gehört zur DataTable auch ein UniqueConstraint mit IsPrimaryKey = true. Wenn eine dieser Bedingungen nicht erfüllt ist, kann der CommandBuilder nicht tätig werden.

Lösung 1: In den Select-Befehl gehört die Spalte hinein, die zum PK gehört (das scheint AdrNr nicht zu sein). Oder ein UniqueConstraint ist hinzuzufügen.

Lösung 2 (weniger angenehm, aber unter Umständen einfacher): Die Commands für die Update-Methode werden manuell erstellt und zugewiesen. Beachte hierbei auch, dass du alles für "WHERE ..." selbst festlegen musst, was den PK ersetzen könnte.

Gruß Jürgen

PS. con.Open/Close können entfallen, das machen Fill und Update automatisch. Die Connection sollte noch besser in einen using-Block gekapselt werden.

09.07.2009 - 11:48 Uhr

Danke, über

WHERE ... IS NULL

habe ich wieder etwas gelernt. Jürgen

09.07.2009 - 09:16 Uhr

Wie wäre es damit (so verstehe ich die Tabellenstruktur):

SELECT * FROM tActors
WHERE ID NOT IN
  ( SELECT FK_Actor FROM tActorsMovies )

Mit deiner Lösung komme ich nicht klar. Dein erster SELECt-Befehl enthält mehrere Fehler:*nicht ID.tActors, sondern tActors.ID *"NOT =" wäre auch Quatsch, sondern "<>" *bei AND besser mit Klammern arbeiten *wie soll ein Wert ID_Movie vom Programm her kommen? das ist doch ein Tabellenfeld, gehört als (in welcher Form auch immer) in den SQL-String *wenn überhaupt, dann sollte das mit Parametern geschehen (hat hier aber keinen Sinn)

Von welchen "3 Feldern" redest du eigentlich?

Gruß Jürgen

PS. Mit JOIN bin ich noch nicht so vertraut; deshalb arbeitet meine schnelle Lösung mit Subselect. Macht man mit JOIN auch Abfragen auf "ungleich"?

09.07.2009 - 09:06 Uhr

Jetzt ist mir aufgefallen, dass es ja sein könnte, dass Daten gelöscht werden müssen. Deswegen möchte die eingetragenen Werte in einer DataGridView darstellen lassen. Wenn man dann eine Zeile makiert , sollen die entsprechenden Werten in den Tabellen gelöscht werden.

Du musst die Daten von der Anzeige trennen. (Auch wenn du das so gelesen hast, hast du es anscheinend nicht umgesetzt.) Die Daten werden aus der Datenbank in eine Datenmenge im Arbeitsspeicher (meistens DataSet/DataTable) geholt und von dort aus z.B. an ein DataGridView gebunden (direkt oder über BindingSource). Änderungen im DGV finden dann automatisch in der DataTable statt (allenfalls wird noch EndEdit benötigt); durch DbDataAdapter.Update gelangen alle Änderungen am Stück in die Datenbank.

Wenn du etwas per Code bearbeiten willst, dann mach das immer - IMMER! - in der DataTable, niemals im DataGridView. Wenn das Markieren einer Zeile einen Löschen-Befehl auslösen soll, geht das sowieso über ein Ereignis, und das soll sich mit der DataTable befassen.

Jürgen

08.07.2009 - 17:51 Uhr

Jürgen : ich arbeite immer mit con.Open und con.Close, da meine Routinen auch mit Transaktionen arbeiten können, und da braucht man das ja.

Tja, es kommt in der Tat immer auf den Gesamtzusammenhang an. Wenn in einer Schleife mehrere Update-Anweisungen nacheinander kommen (wie oben), ist es sinnvoll, vorher einmal Open und nachher einmal Close auszuführen - ähnlich wie bei einer Transaction. (Das ist doch dann implizit eine einzige Transaction, oder?) Aber direkt vor dem Update ein Open und danach ein Close, würde eher nicht passen.

con.Open() bzw. ds.Update() auch noch in einen try-Block packen, denn das kann auch schiefgehen.

Volle Zustimmung!

Ich denke, wir sind uns ziemlich einig im sinnvollen Vorgehen. Wir sind uns nur nicht ganz einig, wenn wir ein "Standardverfahren" empfehlen.

Jürgen

08.07.2009 - 17:41 Uhr

Hallo,

du machst zwei Fehler: Für Access ist Oledb der richtige DbProvider, aber dafür passen SqlParameter nicht. OledbParameter verlangen "?" als Teil des Sql-Strings. Siehe [Artikelserie] Parameter von SQL Befehlen

Nebenbei: die Zwischenvariable "lb7" ist überflüssig, den Wert kannst du direkt in Label.Text eintragen. Die DbConnection sollte besser in einen using-Block eingebaut werden; das erspart auch Close + Dispose.

Jürgen

08.07.2009 - 14:18 Uhr

con.Open und con.Close würde ich in die gleiche Methode packen, möglichst nah beieinander.

Noch besser ist es, dies ganz wegzulassen, denn sowohl Fill als auch Update machen das automatisch.

Viel wichtiger wäre es noch, die Connection in einen using-Block zu kapseln, damit sie nach Erledigung automatisch "weg" ist.

Jürgen

08.07.2009 - 10:12 Uhr

Entschuldige Bernd, aber in diesem Fall passt dein Rat meiner Ansicht nach nicht besonders: Solange Tobi sich noch nicht klar ist darüber, wie DataSet und Datenbanken zusammenarbeiten, wobei hier anscheinend noch eine CSV-Datei ins Spiel kommt, hilft ein einfacher Hinweis auf DbCommandBuilder wenig - ganz abgesehen davon, dass ich sowohl den Hinweis darauf als auch den Link auf dein HowTo schon gebracht hatte. Jürgen

08.07.2009 - 08:50 Uhr

Das würde dann bedeuten, dass mir das DataSet in erster Linie garnichts bringt.

Wenn es dir im Moment "nur" um das Kopieren von einer DB-Tabelle in eine andere DB-Tabelle geht, nämlich um INSERT ... SELECT, dann ist das so. Wozu Daten aus der DB in das DataSet (Arbeitsspeicher) holen, wenn sie in der DB landen sollen.

ich müsste den insert string in einer schleife für jedes row einer tabelle im dataset neu 'generieren' und ausführen, oder liege ich da falsch?

Das ist nur eine von mehreren Möglichkeiten, und zwar die schlechteste. Dies gilt aber auch nur dann, wenn die Daten (aus welchem Grund auch immer) schon im DataSet liegen.

Deshalb hatte ich ja schon oben geschrieben:

dann musst du uns auf jeden Fall verraten, auf welchem Weg die Daten in das DataSet hineingekommen sind.

In der o.g. Exception lese ich gerade, dass dein Projekt etwas mit CSV-Import zu tun hat. (Ich liebe Fragesteller, die wichtige Informationen verschweigen oder verstecken...) Damit kannst du das Problem so lösen:1.Erstelle einen DbDataAdapter zum Einlesen der CSV-Daten, z.B. wie unter ConnectionStrings mit OleDb und Schema.ini oder in einer der Lösungen bei CodeProject beschrieben. 1.Achtung: Setze dabei **AcceptChangesDuringFill **auf false. 1.Erzeuge einen neuen SQLite-DbDataAdapter mit einem **InsertCommand **(oder mit SelectCommand und DbCommandBuilder). 1.Führe dafür **DbDataAdapter.Update **aus.

Erläuterungen zu diesem Vorgehen ergeben sich aus 🛈 Kap.25 ff. sowie :rtfm: zu den genannten Stichworten.

Jürgen

07.07.2009 - 18:44 Uhr

Das mit einem Tutorial ist ein Problem, weil bei dir mindestens zwei Bereiche zusammenkommen: zum einen die SQL-Befehle, die innerhalb der Datenbank wirken, und zum anderen die Klassen und ihre Methoden, die für die Datenmenge im Arbeitsspeicher und für den Datenaustausch mit der Datenbank zuständig sind. Beides solltest du auch beim Lernen trennen; wenn du Probleme mit der Umsetzung hast, musst du überlegen (und bei der Fragestellung und möglichen Lösungen beachten), zu welchem Teilbereich dies gehört.

Zu den SQL-Befehlen hat dir Jack einen FAQ-Link genannt.

Für die Arbeit in einem C#-Programm gibt es 🛈 Kap.25 ff. oder (sehr knapp gehalten) Datenbanken How-To.

Konkret: Im INSERT-Befehl braucht man dann die VALUES-Auflistung, wenn du einzelne Zeilen hinzufügst. Deine Variante mit SELECT holt alle Daten aus einer zweiten Tabelle (Achtung: eine Tabelle der DB, nicht eine DataTable des Programms!) und fügt sie in die erste Tabelle ein. Das geht natürlich nur dann, wenn die Spalten (Felder) und ggf. Inhalte (siehe PrimaryKey) zueinander passen.

Eine solche Aufgabe soll direkt innerhalb der DB abgearbeitet werden; es gibt normalerweise keinen Grund, die Daten abzuholen und zurückzuspeichern. Der Befehl wird ohne DbDataAdapter einfach mit DbCommand.ExecuteNonQuery ausgeführt.

Gruß Jürgen

07.07.2009 - 18:00 Uhr

Möglich ist es über Application.OpenForms und eine foreach-Schleife; aber dabei sind Risiken und Nebenwirkungen (wegen der Reihenfolge des Schließens unter Berücksichtigung von Parametern beim Öffnen) zu befürchten.

Jürgen

/Edit: nicht schnell genug

07.07.2009 - 16:51 Uhr

RecordsAffected hat nur begrenzte Aussagekraft. Siehe :rtfm: SqlDataReader

Die IsClosed-Eigenschaft und die RecordsAffected-Eigenschaft sind die einzigen Eigenschaften, die nach dem Schließen von SqlDataReader aufgerufen werden können. Obwohl jederzeit auf die RecordsAffected-Eigenschaft zugegriffen werden kann, solange der SqlDataReader vorhanden ist, sollten Sie immer zuerst Close aufrufen, bevor der Wert von RecordsAffected zurückgegeben wird, um einen korrekten Rückgabewert zu erhalten.

Vielleicht liegt das Problem tatsächlich nur daran, dass du die Zeilenzahl zu einem "falschen Zeitpunkt" abfragst.

Für die Übergabe der Parameter kannst du doch auch eine List<IfxParameter> verwenden. "Sie hat keinen Konstruktor" ist natürlich Quatsch, jede Klasse hat einen Konstruktor. Dieser ist allerdings protected und kann nicht selbst genutzt werden.

Ob Direction Output funktionieren kann, hängt natürlich von den Input- und Output-Parametern der StoredProcedure ab.

Jürgen

07.07.2009 - 15:49 Uhr

Dann schau erstmal nach, wozu :rtfm: DbDataAdapter.Fill da ist. Dann überlege, was man zum Speichern benutzen könnte. Dann musst du die Voraussetzungen für diese Methode prüfen und sicherstellen. Wenn du dazu Fragen hast, dann musst du uns auf jeden Fall verraten, auf welchem Weg die Daten in das DataSet hineingekommen sind.

Jürgen

@JAck30lena
Ob eine Insert- oder Update-Methode passen, hängt sehr von den Umständen ab. Bezogen auf InsertCommand usw. hättest du recht; aber ob ihm das im Moment weiterhilft?

07.07.2009 - 15:46 Uhr

Schau in :rtfm: Main-Methode. Da steht nichts von "Console" oder "WinForms". Schau die Grundstruktur einer WinForms-Anwendung an, wie sie die IDE vorlegt - insb. Program.cs. Dann stellst du fest, dass die Frage wirklich überflüssig war (vor allem wenn du die Struktur einer Konsolenanwendung kennst). Jürgen

07.07.2009 - 15:41 Uhr

Hallo,

dein Code sieht aus wie "doppelte Arbeit": zuerst wird ein DbCommand erzeugt, Teile davon werden an eine andere Methode übergeben, diese Methode erzeugt einen DbCommand. Kann man das nicht besser verknüpfen?

Ich vermisse:*Code-Markierung, dafür ist der #-Button da *Paramter.Direction = Output, wenn du etwas abfragen willst

Außerdem kommt es mir kritisch vor, dass der DataReader als Rückgabewert verarbeitet wird. Er steckt zwar in einem using-Block und ist deshalb vor Missbrauch geschützt; aber er ist so empfindlich, dass ich davon abraten würde.

Gruß Jürgen

PS. Unter [Artikelserie] Parameter von SQL Befehlen ist Informix nicht enthalten. Falls du es für sinnvoll hältst, kannst du mir per PN eine Ergänzung des 3. Beitrags schicken.

07.07.2009 - 15:22 Uhr
Main(string[] args)

Aber das ist so grundlegend, dass du dich zunächst mit Grundlagen beschäftigen solltest, z.B. 🛈 📗 Siehe auch Wie poste ich richtig? Punkt 1.1.1

Jürgen

06.07.2009 - 19:48 Uhr

Vielleicht kannst du dich von den Delphi-Lösungen unter
kleine String-Math-Lib und Mathe mit Strings inspirieren lassen. Jürgen

06.07.2009 - 14:51 Uhr

Ich verweise jetzt nochmals auf den speziellen DbProvider, der über ConnectionStrings zu finden ist. Dann sind statt der Sql-Klassen für MS-SQL die Ads-Klassen zu verwenden; das wäre auf jeden Fall "um Klassen besser" als OleDb oder gar Odbc. Jürgen

06.07.2009 - 10:58 Uhr

Das hängt zusammen mit der Schreibweise von Strings im Code, siehe auch [FAQ] Was bedeutet das @ (=at) vor String-Literalen?, ist aber auch sehr Grundlagenwissen, siehe Wie poste ich richtig? Punkt 1.1.1 (fällt hier nur nicht so unmittelbar auf).

Jürgen

05.07.2009 - 13:19 Uhr

Hallo,

zum Thema Anfängerforum gab es u.a. kürzlich diese Diskussion. Das Problem liegt nicht darin, dass Anfänger nicht gern gesehen wären, sondern dass Lösungen die Anfängerprobleme nur verlängern, aber nicht beseitigen würden... Und Anfängerfragen werden oft genug beantwortet.

Zu deinem konkreten Problem: Grundsätzlich geht es nicht, dass eine Textdatei immer nur vom Ende her gelesen werden kann. (Genauer: Sämtliche einfachen Lesevorgänge fangen am Dateianfang an.) Es gibt nur die Möglichkeit, über einen **FileStream **zu lesen und sich dabei die **Position **zu merken und vor dem nächsten Lesevorgang dorthin zu springen; Nachteil dabei ist, dass die Read-Methode nicht nach Zeilen lesen kann, sondern nur nach einer Anzahl von Bytes, sodass immer noch passend umgespeichert werden muss.

Zum Problem mit der Analyse der einzelnen Zeilen: Vergiss zunächst einmal die Sonderzeichen im tatsächlichen Text. (Übrigens springst du ständig zwischen "/a" und "\a" hin und her; bitte entscheide dich, was das Problem ist.) Erst dann, wenn du Text im Code schreiben willst, sind die Escape-Zeichen von Bedeutung. Siehe auch [FAQ] Was bedeutet das @ (=at) vor String-Literalen?

Falls du wirklich Zeichen ersetzen musst (nach dem Hinweis von herbivore ist das vermutlich nicht nötig), dann findest du in :rtfm: String-Klasse eine passende Methode. Rate einmal, wie die heißt.

Übrigens hilft auch herbivore Anfängern häufig, wie er das übrigens auch in diesem Thread getan hat. Es kommt vor allem auf die Art der Frage an. (Und deine letzten Kommentare, auch über "sogenannte Grundlagenbücher", verleiden dies.) Ich habe vor allem deshalb noch geantwortet, weil ein Teil deiner Frage sich auf praktische Erfahrungen bezieht, die ein Anfänger nicht haben kann.

Jürgen

04.07.2009 - 18:37 Uhr

Hast du DataSet.EnforceConstraints benutzt (zunächst auf false, später wie der auf true setzen)?

Übrigens: bist du sicher, dass RejectChanges bei deinem Problem hilft? Ich habe Zweifel (wegen der Bedeutung von AcceptChanges), habe mir allerdings deinen Code nicht genauer geprüft.

Gruß Jürgen