Laden...

ID von Tabelle in Variable einlesen, wie?

Erstellt von Trekki1990 vor 15 Jahren Letzter Beitrag vor 15 Jahren 1.887 Views
Trekki1990 Themenstarter:in
503 Beiträge seit 2008
vor 15 Jahren
ID von Tabelle in Variable einlesen, wie?

verwendetes Datenbanksystem: MS SQL Compact 3.5

Hallo liebe Community!

Ich habe mal wieder eine Frage, denn nach stundenlangem suchen habe ich noch immer nichts gefunden.
Problem ist folgendes: Ich brauche die größte "ID" in einer Tabelle. SQL Anweisung habe ich, die klappt auch. Nur wie bekomme ich die zurückgeliefert, dass mein Programm damit was anfangen kann? Datareader habe ich probiert funktioniert aber nicht.


                long id;
                String Statement0 = "SELECT MAX (id) FROM docarchive";
                SqlCeCommand cmd0 = new SqlCeCommand(Statement0, myCon);
                SqlCeDataReader dr = cmd0.ExecuteReader();
                if (dr.Read())
                {
                    id = dr["id"];
                }
                dr.Close();

Ich wollte die ID in den Datentyp long inlesen, wollte er aber nicht machen, da

dr["id"];

object zurückliefert.

Ich hoffe ihr könnt mir einen Tip geben.
Danke schonmal! 😃

R
27 Beiträge seit 2008
vor 15 Jahren

Hoi!

Probier mal:

if (dr.Read())
{
   long.TryParse(dr["id"].ToString(), out id);
}

Gruß

Trekki1990 Themenstarter:in
503 Beiträge seit 2008
vor 15 Jahren

Funktioniert leider auch nicht. Da kommt die Fehlermeldung:

System.IndexOutOfRangeException: id

bei System.Data.SqlServerCe.FieldNameLookup.GetOrdinal(String fieldName)

bei System.Data.SqlServerCe.SqlCeDataReader.GetOrdinal(String name)

bei System.Data.SqlServerCe.SqlCeDataReader.get_Item(String name)

1.200 Beiträge seit 2007
vor 15 Jahren

Wahrscheinlich müsstest du

dr["MAX (id)"]

abfragen.

Aber ich würde an deiner Stelle diese ID eher mittels der ExecuteScalar Methode holen und casten.

Shift to the left, shift to the right!
Pop up, push down, byte, byte, byte!

YARRRRRR!

5.941 Beiträge seit 2005
vor 15 Jahren

Hallo Trekki1990

Wieso brauchst du die grösste ID?
Wenn den neusten Datensatz suchst, nimm entweder IDENTITY oder du stützt dich auf Datum-Felder.

Alles andere ist eine schlechte Idee.

Gruss Peter

--
Microsoft MVP - Visual Developer ASP / ASP.NET, Switzerland 2007 - 2011

Trekki1990 Themenstarter:in
503 Beiträge seit 2008
vor 15 Jahren

@Peter Bucher

Das mit IDENTITY zu machen habe ich wieder verworfen, weil die Methode beim schließen des Forms ausgeführt wird und vorher keine Datensatzänderungen auftreten. Jedenfalls nicht immer.

@GMLOD

Werde ich mal probieren!

Gruß Trekki

J
3.331 Beiträge seit 2006
vor 15 Jahren

Hallo,

so würde es gehen:


                long id;
                String Statement0 = "SELECT MAX (id) FROM docarchive";
                SqlCeCommand cmd0 = new SqlCeCommand(Statement0, myCon);
                SqlCeDataReader dr = cmd0.ExecuteReader();
                if (dr.Read())
                {
                    id = dr.GetInt64(0);  //  passende Methode incl. Konvertierung
                }
                dr.Close();

Aber die Vorschläge von GLMOD und Peter Bucher sind besser. Jürgen

5.941 Beiträge seit 2005
vor 15 Jahren

Hallo Trekki1990

Ist doch kein Problem.
Du kannst doch einfach die letzte hinzugefügte ID per IDENTITY auslesen und im Speicher halten.

Andernfalls wie gesagt über das Datum / Uhrzeit.
Bei deinem speziellen Anwendungsfall wird wohl nichts schiefgehen, also kannst du das auch so machen.

Gruss Peter

--
Microsoft MVP - Visual Developer ASP / ASP.NET, Switzerland 2007 - 2011

3.511 Beiträge seit 2005
vor 15 Jahren

Wenn du nur einen einzigen Wert abfragst in einem Statement, dann geh über ExecuteScalar.


String Statement0 = "SELECT ISNULL(MAX(id), 0) FROM docarchive";
SqlCeCommand cmd0 = new SqlCeCommand(Statement0, myCon);
int id = (int)cmd0.ExecuteScalar();

Das ISNULL verhindert, das NULL zurückgeliefert wird, wenn noch kein einziger Datensatz vorhanden ist.

Ansonsten wie Peter sagt, über Datum/Zeit gehen.

"Jedes Ding hat drei Seiten, eine positive, eine negative und eine komische." (Karl Valentin)

X
1.177 Beiträge seit 2006
vor 15 Jahren

huhu,

Es gibt auch keinen Spaltennamen in deinem SQL-Befehl. Entweder Spaltennamen anfügen oder auf die erste Spalte zugreifen.

 Select max(id) as max_id from

long id = 0;
if (dr.Read())
{
  id = (long)dr["max_id"];
  id = (long)dr[0];
}

😃

Xynratron

Edit: naja, wegwerfen wollte ich das geschrieben dann auch nicht, nur weil schon so viele gepostet haben^^

Herr, schmeiss Hirn vom Himmel - Autsch!

Die Erfahrung zeigt immer wieder, dass viele Probleme sich in Luft auslösen, wenn man sich den nötigen Abstand bzw. Schlaf gönnt.

Trekki1990 Themenstarter:in
503 Beiträge seit 2008
vor 15 Jahren

Danke für eure Antworten!!! Das hat mir geholfen danke. 😉

Trekki1990 Themenstarter:in
503 Beiträge seit 2008
vor 15 Jahren

@Khalid

Bei deiner Methode gibt er mir folgende Fehlermeldung zurück (habe allerdings bei der SQL Anweisung ein Alias machen müssen):

Die angegebene Umwandlung ist ungültig.

String Statement0 = "SELECT ISNULL(MAX(id), 0) AS dca FROM docarchive";
SqlCeCommand cmd0 = new SqlCeCommand(Statement0, myCon);
int id = (int)cmd0.ExecuteScalar();
F
10.010 Beiträge seit 2004
vor 15 Jahren

Und es ist doch ganz einfach mal zu verstehen was da passiert,
um dann ggf den fehler abzustellen:


...
object retval = cmd0.ExecuteScalar();
if( retval != null )
  id = Convert.ToInt32(retval);

Wenn du da jetzt auf das If den debugger setzt, kannst du sehen was Du da
zurückbekommen hast, und dann auch erkennen warum das vorher nicht ging.

Du hast aber immer noch nicht erzählt wofür du das brauchst, nur warum du meinst
es so lösen zu müssen.

Trekki1990 Themenstarter:in
503 Beiträge seit 2008
vor 15 Jahren

Also ich beschreibe mal kurz:

  1. Nutzer öffnet Programm
  2. Nutzer schreibt etwas in die richTextBox
  3. Nutzer schließt das Programm
  4. Beim schließen (FormClosing) wird Text mit Zeit-/Datumsstempel in Datenbank geschrieben
    4.1 letzten Eintrag suchen
    4.2 Ist letzter Eintrag ungleich des Inhalts in der richTextBox -> schreibe Daten
  5. Schließe Connection

So das ist der grundlegende Ablauf. Es funktioniert ja auch, aber nur wenn die Datenbank mindestens einen Datensatz enthält.
Das ist das Problem.

F
10.010 Beiträge seit 2004
vor 15 Jahren

Dein problem ist also, das DU nicht abfängst, ob noch kein Datensatz da ist!

Trekki1990 Themenstarter:in
503 Beiträge seit 2008
vor 15 Jahren

So habe noch mal ein bisschen gebastelt. Jetzt funktioniert alles. Ohne eure Hilfe hätte ich es aber nicht geschafft. Danke!

5.941 Beiträge seit 2005
vor 15 Jahren

Hallo Trekki1990

Und kannst du uns deine Lösung offenbaren?

Gruss Peter

--
Microsoft MVP - Visual Developer ASP / ASP.NET, Switzerland 2007 - 2011

Trekki1990 Themenstarter:in
503 Beiträge seit 2008
vor 15 Jahren

Ist ziemlich dirty, aber ich machs mal:

try
            {
                String Statement0 = "SELECT ISNULL(MAX(id), 0) AS dca FROM docarchive";
                SqlCeCommand cmd0 = new SqlCeCommand(Statement0, myCon);

                object retval = cmd0.ExecuteScalar();
                if (retval != null)
                {
                    id = Convert.ToInt32(retval);
                }
                if (id == 1)
                {
                    String Statement1 = "INSERT INTO docarchive (doccontent, timestamp) VALUES ('" + richTextBox1.Text + "', '" + DateTime.Now.ToString() + "')";
                    SqlCeCommand cmd1 = new SqlCeCommand(Statement1);
                    cmd1.Connection = myCon;
                    cmd1.ExecuteNonQuery();
                }
                else
                {
                    try
                    {
                        string Statement2 = "SELECT MAX (id) AS dca FROM docarchive";
                        SqlCeCommand cmd2 = new SqlCeCommand(Statement2, myCon);
                        SqlCeDataReader dr0 = cmd2.ExecuteReader();
                        if (dr0.Read())
                        {
                            int.TryParse(dr0["dca"].ToString(), out id1);
                        }
                        dr0.Close();

                        double dbtext;
                        double newtext = richTextBox1.Text.Length;
                        MessageBox.Show(id1.ToString());
                        
                        string strSQL = "SELECT doccontent FROM docarchive WHERE id = " + id1 + ";";
                        SqlCeCommand cmd = new SqlCeCommand(strSQL, myCon);
                        SqlCeDataReader dr1 = cmd.ExecuteReader();
                        if (dr1.Read())
                        {
                            dbtext = dr1["doccontent"].ToString().Length;
                            if (dbtext != newtext)
                            {
                                String Statement1 = "INSERT INTO docarchive (doccontent, timestamp) VALUES ('" + richTextBox1.Text + "', '" + DateTime.Now.ToString() + "')";
                                SqlCeCommand cmd1 = new SqlCeCommand(Statement1);
                                cmd1.Connection = myCon;
                                cmd1.ExecuteNonQuery();
                            }
                        }
                        dr1.Close();
                        myCon.Close();
                     }
                     catch (Exception dr1ex)
                     {
                         MessageBox.Show("Es ist ein Fehler aufgetreten:\n\n" + dr1ex.Message);
                     }
                 }
             }
             catch (Exception ex)
             {
                 MessageBox.Show("Es ist ein Fehler aufgetreten:\n\n" + ex.Message);
             }
Trekki1990 Themenstarter:in
503 Beiträge seit 2008
vor 15 Jahren

Ich werd den bei Gelegenheit noch optimieren.

F
10.010 Beiträge seit 2004
vor 15 Jahren

Wieder ein "schönes" Beispiel wie man DB Zugriffe NICHT machen sollte.
Parameter gehören nicht in den Sqlstring gefriemelt, sondern in die Parametercollection
des Commands.
Und das hat nichts mit Optimieren zu tun, such mal nach "Sql-Injection".
Auch sieht es so aus, als wenn Du eine globale Connection hättest, auch das
ist unter .NET contraproduktiv.

Genauso, das du bei allen Selects das ExecuteScalar benutzen könntest, und
das du die 2. und 3. Abfrage als join vereinfachen könntest.

Und mit nem vernünftigen ORMapper wäre das ganze dann ein 5 Zeiler geworden.

Trekki1990 Themenstarter:in
503 Beiträge seit 2008
vor 15 Jahren

Ich stimme dir in allem zu FZelle. Aber ich beschäftige mich zum ersten mal mit Datenbanken. Ich will ja auch erstmal verstehen was da passiert und wenn ich weiß da passiert, dann kann ich mich mit fortgeschritteneren Möglichkeiten befassen.

5.941 Beiträge seit 2005
vor 15 Jahren

Salute Treekki1990

Schau dir dazu auch noch das an:

Gruss Peter

--
Microsoft MVP - Visual Developer ASP / ASP.NET, Switzerland 2007 - 2011

Trekki1990 Themenstarter:in
503 Beiträge seit 2008
vor 15 Jahren

Danke Peter! Das ist ein gutes Dokument. Werde mich mit beschäftigen und guten Code schreiben ^^ 👍

F
10.010 Beiträge seit 2004
vor 15 Jahren

Halte ich für die falsche herangehensweise.

Erst die grundlagen erlesen, dann Probieren, nicht andersrum.
Spart Zeit, Nerven und im professionellen Umfeld damit auch viel Geld.

Trekki1990 Themenstarter:in
503 Beiträge seit 2008
vor 15 Jahren

FZelle ist klar, aber ich bin nicht im professionellen Bereich tätig. Es ist mehr ein Hobby.
Ich arbeite nach dem Prinzip "Learning by doing" und habe dabei immer gut lernen können. Es hat sich auch mehr verfestigt. Ich bin ein praktischer Mensch.
Außerdem ist es ja jedem selber überlassen wie er an ein Problem herangeht, jeder Mensch macht es so wie er es am besten kann. 😃

F
10.010 Beiträge seit 2004
vor 15 Jahren

Naja, wenn Du durch diese Art der herangehensweise aber diejenigen
vergraulst die dir bei echten Problemen helfen könnten, dann hast Du
aber mit Zitronen gehandelt.

Trekki1990 Themenstarter:in
503 Beiträge seit 2008
vor 15 Jahren

Zitronen sind lecker! ^^
Ich bin ja auch dankbar für Lösungsvorschläge und sie helfen mir ja auch. Bloß ich kann ja nicht alles sofort umsetzen, bin ja kein Supermensch.