Laden...

Wieso verdoppelt sich die ganze SQLite Table, wenn ich update?

Erstellt von C4RL0 vor 3 Jahren Letzter Beitrag vor 3 Jahren 1.468 Views
C4RL0 Themenstarter:in
96 Beiträge seit 2012
vor 3 Jahren
Wieso verdoppelt sich die ganze SQLite Table, wenn ich update?

Moin zusammen,

ich lese eine SQLite DB Tabelle mit "SELECT * ..." in eine DataTable, welche ich per Databinding incl. BindingNavigator an Textboxen binde.
Wenn ich nun mit folgender Methode die DataTable zurückspeichern möchte, verdoppelt sich die DB Tabelle, d.h. es wird nicht geupdatet sondern insertet. Ich weiß nur nicht, warum?

Hat jemand eine Idee?

        public static int SaveDataTable(DataTable DT)
        {
            int rowsUpdated = 0;
            try
            {
                using (SQLiteConnection cnn = new SQLiteConnection(_ConnectionString))
                {
                    
                    using (SQLiteCommand myCommand = cnn.CreateCommand())
                    {
                        myCommand.CommandText = string.Format("SELECT * FROM {0}", DT.TableName);
                        using (SQLiteDataAdapter myDataAdapter = new SQLiteDataAdapter(myCommand))
                        {
                            using (SQLiteCommandBuilder builder = new SQLiteCommandBuilder(myDataAdapter))
                            {
                                cnn.Open();
                                rowsUpdated = myDataAdapter.Update(DT);
                            }
                        }
                    }
                }
                return rowsUpdated;
            }
            catch (Exception Ex)
            {
                MessageBox.Show(Ex.Message);
                return rowsUpdated;
            }
        }

Edit: Ich habe festgestellt, dass, wenn ich DT.AcceptChanges() vorher ausführe, obiges nicht passiert. Allerdings werden dann auch keine Changes gespeichert. D.h. wieder kein Update.


Gruß
Carlo

"Palabras que no coinciden con hechos no valen nada."

F
10.010 Beiträge seit 2004
vor 3 Jahren

Und wie hast du die DT erzeugt?

Der DataAdapter macht genau was er soll, nicht was Du denkst, was er machen soll.

T
2.222 Beiträge seit 2008
vor 3 Jahren

Klingt auch nach einem Fall von kein PK oder neuen PKs im DataTable.
Ansonsten würde es beim inserten auch knallen, wenn du doppelte Daten inserten würdest.

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

4.938 Beiträge seit 2008
vor 3 Jahren

Der Fehler ist recht trivial (wenn man weiß wieso):
Du mußt selbstverständlich dieselbe SQLiteDataAdapter-Instanz beim Lesen und Schreiben benutzen!

F
10.010 Beiträge seit 2004
vor 3 Jahren

Das stimmt nicht, das ist vollkommen unabhängig voneinander.

Aber wenn jemand schon in Erwägung zieht AcceptChanges zu benutzen,
dann ist da schon etwas am Grundverständnis nicht OK.

Deswegen ist es wichtig zu wissen wie die DT entstanden ist.

C4RL0 Themenstarter:in
96 Beiträge seit 2012
vor 3 Jahren

Also die DT entsteht folgendermaßen:

        internal static DataTable GetDataTable(string tablename)
        {
            using (DataTable dataTable = new DataTable())
            {
                using (SQLiteConnection connection = new SQLiteConnection(_ConnectionString))
                {
                    using (SQLiteCommand command = new SQLiteCommand(connection))
                    {
                        using (SQLiteDataAdapter adapter = new SQLiteDataAdapter(command))
                        {
                            command.CommandText = string.Format("SELECT * FROM {0}", tablename);
                            connection.Open();
                            adapter.Fill(dataTable);
                            connection.Close();
                            return dataTable;
                        }
                    }
                }
            }
        }

Gruß
Carlo

"Palabras que no coinciden con hechos no valen nada."

16.827 Beiträge seit 2008
vor 3 Jahren

Schau Dir an wie ein using() funktioniert.
Du disposed die DataTable und gibst sie dann zurück - das macht kein Sinn.



        internal static DataTable GetDataTable(string tablename)
        {
                using (SQLiteConnection connection = new SQLiteConnection(_ConnectionString))
                using (SQLiteCommand command = new SQLiteCommand(connection))
                using (SQLiteDataAdapter adapter = new SQLiteDataAdapter(command))
                {
                            command.CommandText = string.Format("SELECT * FROM {0}", tablename);
                            connection.Open();
                            adapter.Fill(dataTable);
                            connection.Close();
                            return dataTable;
                }
        }


Aber ich drücke mich mal vorsichtig aus, dass der ganze Code hier "suboptimal" ist.
Er verletzt zig Prinzipien und Empfehlungen; und darüber hinaus untestbar (=> [Artikel] Unit-Tests: Einführung in das Unit-Testing mit VisualStudio )
Persönlich weiß ich auch nicht, ob das Grundkonstrukt mit der Verbindungsverwaltung und der DataTable so überhaupt funktionieren kann. Das weiß jemand vielleicht besser, der noch DataTables verwendet (ich seit Jahren nicht mehr).

PS: wie auch Parameter ( [Artikelserie] SQL: Parameter von Befehlen ) muss man Table Names behandeln, um sich zu schützen


var builder = new SqlCommandBuilder();
string escapedTableName = builder.QuoteIdentifier(tableName);

C4RL0 Themenstarter:in
96 Beiträge seit 2012
vor 3 Jahren

Aber ich drücke mich mal vorsichtig aus, dass der ganze Code hier "suboptimal" ist. Er verletzt zig Prinzipien und Empfehlungen; und darüber hinaus untestbar.

Die Aussage ist völlig okay, da weiß ich, dass ich noch was zu tun habe. Mit dem Testen habe ich mich eh zu wenig beschäftigt. 😉

Persönlich weiß ich auch nicht, ob das Grundkonstrukt mit der Verbindungsverwaltung und der DataTable so überhaupt funktionieren kann. Das weiß jemand vielleicht besser, der noch DataTables verwendet (ich seit Jahren nicht mehr).

Was verwendest Du statt DataTables?


Gruß
Carlo

"Palabras que no coinciden con hechos no valen nada."

16.827 Beiträge seit 2008
vor 3 Jahren

Ich hab nie den Bedarf eine gesamte Datenbanktabelle in den Speicher einer Anwendung zu laden. Würde in dem Umfeld, in dem ich meistens bei Kunden bin, auch gar nicht gehen oder gar sinn machen.
Ich arbeite daher prinzipiell mit Selektionen und Projektionen, zB dann mit Entity Framework oder Dapper und entsprechenden Modellen und Architekturprinzipien.

F
10.010 Beiträge seit 2004
vor 3 Jahren

Ganz abgesehen davon, der TableAdapter hat einen Contructor, der bereits den Connectionstring entgegennimmt.

Aber T-Virus hat eine gute Anmerkung gemacht, wie ist denn der Key der DB erstellt?