Autor |
Beitrag |
ffgorcky
      
Beiträge: 573
WIN XP/2000 & 7Prof (Familie:Win95,Win98)
|
Verfasst: Mo 15.03.10 21:19
Hallo liebes Forum,
hier noch mal ein eigener Thread für dieses Thema, wo ich immer noch nicht weiter komme:
Ich hatte versucht, durch kopieren und abwandeln des Erstbeitrags des Threads Datenbanken mit OleDb und SQL auch eine Abfrage hinzubekommen.
Aber der Compiler sagt mir: ''Der Name "Settings" ist im aktuellen Kontext nicht vorhanden''.
Also wie muss ich den denn dazu Konstruieren?
Hier mal mein momentaner Versuch, wo er die Meldung bringt:
C#-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17:
| public void fuegeEineNeuePersonHinzu(string Name, decimal alter, bool geschlecht) { string sAlter = i16.ConvertToString(alter); comboBoxPersonenAuswahl.Items.Add(Name); comboBoxPersonenAuswahl.SelectedIndex = comboBoxPersonenAuswahl.Items.Count-1; OleDbConnection Con = new OleDbConnection(); Con.ConnectionString = Settings.Default.ConString; Con.Open(); string SQL = "INSERT Name="+Name+" Alter="+alter+" Geschlecht="+geschlecht+" TO
Personen"; OleDbCommand Dat = new OleDbCommand(); Dat.CommandText = SQL; Dat.Connection = Con; OleDbDataReader Reader = Dat.ExecuteReader(); } |
Ich kann leider auch nichts mit JüThos Hinweis auf diesen Thread anfangen.
Die Abkürzungen kenne ich ja, aber das bringt mich trotzdem nicht weiter in meinem Problem "Settings".
|
|
Ralf Jansen
      
Beiträge: 4708
Erhaltene Danke: 991
VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
|
Verfasst: Mo 15.03.10 22:00
Öffne die Properties deinen Projekts. Dort wirst du unter anderem einen Tab Namens Settings (oder das äquivalent deiner Sprachversion der IDE) finden.
Hier siehst du nun ein Grid mit Einstellungen (Name, Type, Scope, Value) in dem du einfach deinen Connectionstring mit Name = "ConString" und Type = "(Connectionstring)" eintragen kannst. Als Value halt deinen konkreten Connectionstring dort eintragen. Aus den Eintragungen wird dann im folgenden automatisch die Settings Klasse im Properties Namespace erzeugt. Die ConString Property solltest du also eher mit Properties.Settings.Default.ConString ansprechen.
Über dem Grid auf dem Settings Tab solltest du übrigens auch einen Link in die Hilfe mit Detailinformation finden.
|
|
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 15.03.10 23:49
Hallo Ronald,
tut mir leid, wenn ich zusätzlich viel Wasser in den Wein gießen muss; aber du gehst mehrere falsche Wege. Einen Weg, wie der ConnectionString gespeichert werden kann, hat Ralf beschrieben. Dazu kommt folgendes:
1. Eine Connection sollte immer nur für die aktuelle Notwendigkeit erzeugt und geöffnet werden; danach muss sie i.d.R. geschlossen und aufgelöst werden. Das macht man am besten mit einem using-Block.
2. SQL-Befehle dürfen niemals per String-Verknüpfung erzeugt werden! Das erzeugt miserablen Code (bei dir: i16.ConvertToString(alter) - was ist das für eine seltsame Konstruktion, wo es doch alter.ToString gibt?!), gibt Probleme mit Formatierungen (dein INSERT-Befehl ist wegen fehlender Hochkommata sowieso ungültig und außerdem völlig falsch aufgebaut) und öffnet Missbrauch Tür und Tor, siehe Wikipedia: SQL-Injection.
3. Ein INSERT-Befehl ist etwas zum Speichern, nicht zum Lesen. ExecuteReader ist also abwegig. (Auch hierfür gilt: Schau in die SDK-Doku, was es für Alternativen gibt).
Ein Alter würde ich übrigens nicht als decimal definieren. Es kommt sicher nicht auf die Genauigkeit von mehr als 15 Stellen an.
Eine vernünftige Lösung sieht kurz gefasst so aus:
C#-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17:
| public void fuegeEineNeuePersonHinzu(string name, double alter, bool geschlecht) { comboBoxPersonenAuswahl.Items.Add(name); comboBoxPersonenAuswahl.SelectedIndex = comboBoxPersonenAuswahl.Items.Count-1;
using( OleDbConnection con = new OleDbConnection(Properties.Settings.Default.ConString) ) { string sql = "INSERT INTO Personen (Name, Alter, Geschlecht)" + " VALUES (?, ?, ?);"; OleDbCommand cmd = new OleDbCommand(sql, con); cmd.Parameters.AddWithValue( "@Name", name ); cmd.Parameters.AddWithValue( "@Alter", alter ); cmd.Parameters.AddWithValue( "@Geschlecht", geschlecht ); con.Open(); cmd.ExecuteNonQuery(); } } |
Ist das nicht viel übersichtlicher? con.Close und con.Dispose brauche ich nicht, weil das durch using automatisch erledigt wird. Wenn du willst, kannst du con.Open und den Execute-Befehl in try-catch einbinden und den Rückgabewert von Exec abfragen, um zu erfahren, ob das Einfügen erfolgreich war.
Noch ein paar Hinweise:
OpenBook VC# Kap.25 ff. zur Einführung in ADO.NET
Einführung in SQL, denn du musst schon wissen, wie ein SQL-Befehl auszusehen hat
[Artikelserie] Parameter von SQL Befehlen dazu, dass und warum mit Parameters gearbeitet werden muss
[Artikel] Ressourcen schonen - Datenbanken richtig öffnen und schließen als Erläuterung zum using-Block
Schau in die Doku! - Möglichkeiten der Informationsgewinnung
.NET Richtlinien für Namen vor allem wegen Groß- und Kleinschreibung
Gruß Jürgen
|
|
ffgorcky 
      
Beiträge: 573
WIN XP/2000 & 7Prof (Familie:Win95,Win98)
|
Verfasst: Di 16.03.10 14:29
Hallo Jürgen,
Deine using-Lösung ist gut!
Daran konnte ich mich leider nicht mehr erinnern.
- jetzt bringt er mir aber genau in dieser Zeile 7(in Deinem Quelltext) zum ConString diese Fehlermeldung:
--------------------------------------------------------------------------------------------------------------------------------
"VisuelleWahrnehmung_VersuchNr2.Properties.Settings" enthält keine Definition für "ConString",
und es konnte keine Erweiterungsmethode "ConString" gefunden werden,
die ein erstes Argument vom Typ "VisuelleWahrnehmung_VersuchNr2.Properties.Settings" akzeptiert.
(Fehlt eine Using-Direktive oder ein Assemblyverweis?) 72 90 VisuelleWahrnehmung-VersuchNr2
--------------------------------------------------------------------------------------------------------------------------------
- Also wie binde ich das jetzt ein?
- Oder fehlt da jetzt wirklich auch noch ein using-Verweis?
|
|
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 16.03.10 15:35
Ralf hat beschrieben, wie der ConnectionString registriert werden kann; er hat den Namen ConString vorgeschlagen. Er hat dir aber nicht über die Schultern geschaut, was du tatsächlich geschrieben hast. Du musst denselben Namen benutzen, den du in den Properties angegeben hast.
Das ist aber eine Fehlermeldung, der du selbst nachgehen kannst und musst.
Jürgen
|
|
ffgorcky 
      
Beiträge: 573
WIN XP/2000 & 7Prof (Familie:Win95,Win98)
|
Verfasst: Di 16.03.10 15:37
Und ich habe eine Komponente, die mir decimal für das Alter zurückgibt:
numericUpDownAlter.Value
Wie wandele ich das in double um?
|
|
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 16.03.10 15:41
ffgorcky hat folgendes geschrieben : | Wie wandele ich das in double um? |
1. SDK-Doku/MSDN/Hilfe - Stichwort: Was gibt es zur decimal-Klasse?
2. Wie kann man etwas in etwas umwandeln? Wie kann das in Englisch heißen?
Etwas mehr Eigeninitiative bitte! Jürgen
|
|
ffgorcky 
      
Beiträge: 573
WIN XP/2000 & 7Prof (Familie:Win95,Win98)
|
Verfasst: Di 16.03.10 16:40
Also laut diesem Link gibt es dafür ziemlich viele Übersetzungen in Englisch. - Mal sehen, welche in C# die richtige ist...
|
|
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 16.03.10 16:58
Nicht so kompliziert denken, sondern viel primitiver: umwandeln in double oder nach double. Klingelt's jetzt?
Noch'n Tipp: Welche Methode gibt es für jede Klasse? Was macht die? Hilft diese Erkenntnis weiter bei dem Problem mit double?
Und natürlich das, was ich schon sagte: selbst in der SDK-Doku/MSDN/Hilfe unter decimal-Klasse / Alle Member nachlesen.
Jürgen
|
|
ffgorcky 
      
Beiträge: 573
WIN XP/2000 & 7Prof (Familie:Win95,Win98)
|
Verfasst: Di 16.03.10 18:29
|
|
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 16.03.10 19:14
Das ist eine von 83 anderen. Was hältst du davon:
C#-Quelltext 1:
| alter = Decimal.ToDouble(numericUpDownAlter.Value); |
Versteh mich nicht falsch: Das ist jetzt weitgehend Geschmackssache; deine und meine Lösung machen faktisch dasselbe (nicht nur das gleiche). Es gibt aber eine Reihe von Situationen, wo die Convert-Methoden mindestens äußerst ungünstig sind; deshalb empfehle ich, darauf möglichst zu verzichten.
Der entscheidende Punkt ist: Du hast ToDouble als Lösung gefunden; das kannst du hoffentlich auf künftige Bedürfnisse übertragen und sofort direkt in der SDK-Doku nach einem solchen Stichwort suchen.
Viel Erfolg weiterhin! Jürgen
|
|
Kha
      
Beiträge: 3803
Erhaltene Danke: 176
Arch Linux
Python, C, C++ (vim)
|
Verfasst: Di 16.03.10 20:17
Oder auch (double)numericUpDownAlter.Value - die Qual der Wahl  .
_________________ >λ=
|
|
ffgorcky 
      
Beiträge: 573
WIN XP/2000 & 7Prof (Familie:Win95,Win98)
|
Verfasst: Di 23.03.10 12:46
So, entschuldigt Leute, dass ich vom Titel-Thema abgewichen bin.
Noch mal eine Frage zu diesem eigentlichen Problem:
Ich habe das hier jetzt als Verbindungszeichenfolge im Bereich Anwendung unter dem Namen "ConString" gespeichert:
Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\NP-Test.mdf;Integrated Security=True;Connect Timeout=30;User Instance=True
und in meinem Entwicklungs-Ordner habe ich auch genau diese Datei liegen.
Aber während der Laufzeit kommt dann immer noch bei dieser Prozedur:
C#-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19:
| public void fuegeEineNeuePersonHinzu(string name, double alter, bool geschlecht) { comboBoxPersonenAuswahl.Items.Add(name); comboBoxPersonenAuswahl.SelectedIndex = comboBoxPersonenAuswahl.Items.Count - 1; using (OleDbConnection con = new OleDbConnection(Properties.Settings.Default.ConString)) { string sql = "INSERT INTO Personen (Name, Alter, Geschlecht)" + " VALUES (?, ?, ?);"; OleDbCommand cmd = new OleDbCommand(sql, con); cmd.Parameters.AddWithValue("@Name", name); cmd.Parameters.AddWithValue("@Alter", alter); cmd.Parameters.AddWithValue("@Geschlecht", geschlecht); con.Open(); cmd.ExecuteNonQuery(); } } |
in der using-Zeile der Fehler:
Zitat: | In ConnectionString wurde kein OLE DB Provider abgegeben.
Anwendungsbeispiel: 'Provider=SQLOLEDB;'. |
|
|
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 23.03.10 13:56
Es ist eben ein Unterschied, welcher DbProvider verwendet wird. Jeder Provider hat seine speziellen Informationen, die er für den ConnectionString braucht.
* Oledb => allgemeiner DB-Zugriff => spezielle Informationen wie "Provider=SQLOLEDB" werden benötigt
* Sql => spezieller DB-Zugriff => nur der Zugriff selbst muss geregelt werden
Wenn du "Data Source=.\SQLEXPRESS" angibst, verwendest du offensichtlich den MS-SQL-Server (und nicht Access). Dann brauchst du die Sql-Klassen statt der Oledb-Klassen.
Die verschiedenen Varianten mit möglichen Verbindungsdaten findest du u.a. unter ConnectionStrings. Du kannst auch den jeweiligen XxxConnectionStringBuilder ausprobieren, welche Teile eingegeben werden müssen, damit einen ConnectionString erzeugen lassen und diesen speichern.
Gruß Jürgen
PS. Es ist möglich, mit Oledb auf den SQL-Server zuzugreifen, aber keinesfalls zu empfehlen. Wenn du für deine Stereo-Anlage zuhause die Auswahl hast zwischen einem hochwertigen Kopfhörer und primitiven Ohrstöpseln, wirst du auch der Qualität den Vorzug geben.
|
|
ffgorcky 
      
Beiträge: 573
WIN XP/2000 & 7Prof (Familie:Win95,Win98)
|
Verfasst: Mo 03.05.10 09:17
Entschuldigt, dass ich hier leider irgendwie nicht weiterkomme.
Im Moment sieht meine Prozedur so 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: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52:
| public void fuegeEineNeuePersonHinzu(string name, double alter, bool geschlecht,bool selbstZusammengebastelteVersionZurUnterscheidungVonDerForumsLösung) { comboBoxPersonenAuswahl.Items.Add(name); comboBoxPersonenAuswahl.SelectedIndex = comboBoxPersonenAuswahl.Items.Count - 1; SqlConnectionStringBuilder conBuilder = new SqlConnectionStringBuilder(); using (SqlConnection con = new SqlConnection(conBuilder.ConnectionString)) { con.ConnectionString = "Data Source=(local);" + "Initial Catalog=NP-Test;" + "Integrated Security=sspi"; string sql = "INSERT INTO Personen (Name, Alter, Geschlecht)" + " VALUES (?, ?, ?);"; SqlCommand cmd = new SqlCommand(con.ConnectionString); cmd.Parameters.AddWithValue("@Name", name); cmd.Parameters.AddWithValue("@Alter", alter); cmd.Parameters.AddWithValue("@Geschlecht", geschlecht); try { con.Open(); try { cmd.ExecuteNonQuery(); con.Close(); } catch (SqlException) { MessageBox.Show("Der Datenbank-Eintrag hat bei geöffneter Datenbank nicht geklappt."); } } catch (SqlException) { MessageBox.Show("Der Datenbank-Eintrag hat nicht geklappt. - Die Datenbank konnte nicht geöffnet werden."); } }
} |
Sie funkioniert aber so nicht.
Da erscheint immer noch die Fehlermeldung ..." Die Datenbank konnte nicht geöffnet werden.".
Kann mir jemand sagen, warum solch eine Meldung kommt?
Heißt das etwa, dass das Datenbank-Programm nicht aktiv ist?
Oder wie kann ich denn mal eine kleine Abfrage machen, in der ich feststellen kann, woran es genau liegt?
|
|
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 03.05.10 09:47
Hallo,
eines deiner Probleme ist, dass du verschiedene Dinge mischst. (Das liegt natürlich auch an den vielen Versuchen.)
1. Beim SqlConnectionStringBuilder werden die einzelnen Bestandteile (DataSource, InitialCatalog usw.) eingetragen. Den ConnectionString setzt der Builder daraus zusammen, dann wird er abgerufen. conBuilder.ConnectionString sollte also niemals links vom Gleichheitszeichen stehen; üblicherweise wird es direkt in den Konstruktor-Aufruf der Connection gesetzt.
Letzteres machst du zwar, aber die Zuweisung der Einzelteile hast du auskommentiert. Also kann im ConnectionString nichts Sinnvolles mehr enthalten sein; also kann keine Datenbank geöffnet werden.
2. Folgendes ist "doppelt gemoppelt":
C#-Quelltext 1: 2: 3:
| con = new SqlConnection(conBuilder.ConnectionString) con.ConnectionString = "Data Source=(local);" + "Initial Catalog=NP-Test;" + "Integrated Security=sspi"; |
3. Hier nimmst du nicht den SQL-Befehl:
C#-Quelltext 1:
| SqlCommand cmd = new SqlCommand(con.ConnectionString); |
4. Beim Sql-Provider müssen die Parameter mit Namen benutzt werden; siehe in der Artikelserie zu den SQL-Parametern den 3. Beitrag.
ffgorcky hat folgendes geschrieben : | Oder wie kann ich denn mal eine kleine Abfrage machen, in der ich feststellen kann, woran es genau liegt? |
Es empfiehlt sich, zuerst mit dem Management Studio eine Verbindung herzustellen, damit der ConnectionString bekannt ist und übernommen werden kann. Danach kann man mit einem SELECT-Befehl experimentieren, um Werte abzurufen und anzuzeigen. Wenn das funktioniert, kommen UPDATE- und INSERT-Befehle an die Reihe.
Wenn du bei catcheine Exception notierst, dann benutze sie auch mit ex.ToString in der Meldung (das liefert die meisten Informationen).
Gruß Jürgen
PS. Der Datenbank-Zugriff hat mit dem ursprünglichen Problem eigentlich nichts mehr zu tun. Vielleicht solltest du einen Moderator bitten, die Diskussion an einer passenden Stelle zu trennen.
|
|
|