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."
Und wie hast du die DT erzeugt?
Der DataAdapter macht genau was er soll, nicht was Du denkst, was er machen soll.
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.
Der Fehler ist recht trivial (wenn man weiß wieso):
Du mußt selbstverständlich dieselbe SQLiteDataAdapter
-Instanz beim Lesen und Schreiben benutzen!
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.
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."
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);
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
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."
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.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
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?