Laden...

SQLite 'On Delete Cascade' funktioniert nicht

Letzter Beitrag vor einem Jahr 6 Posts 867 Views
SQLite 'On Delete Cascade' funktioniert nicht

Hi zusammen,

ich habe in meiner SQLite-Datenbank eine untergeordnete Tabelle 'resKat' die in einer Fremdschlüsselspalte auf die übergeordnete Tabelle 'kategorie' verweist. Die Fremdschlüsselspalte ist auf OnDeleteCascade eingestellt. Lösche ich innerhalb SQLite-Studio eine Zeile aus Tabelle 'kategorie' werden die korrespondierenden Datensätze in 'resKat' automatisch gelöscht.

Die identische SQL-Anweisung aus C# heraus löscht zwar den Datensatz in Tabelle 'kategorie' nicht aber die korrespondierenden Datensätze in 'resKat'. Was mache ich falsch?

         //---------------------------------------------------------------------------------
        //brief: führt DML-Kommandos aus (Insert, Update, Delete)
        private int dml (SQLiteCommand cmd)
        {
            int result = 0;

            try
            {
                dbCon.Open(); //global verfügbar
                result = cmd.ExecuteNonQuery();
            }
            catch (Exception e)
            {
                MessageBox.Show("Ausnahmefehler in 'Form1.dml'\n\nFehler: " + e.Message, "Error",
                                MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            
            dbCon.Close();
            return result;
        }

        ....
        cmd.CommandText = $"delete from kategorie where katId={dgvKat.CurrentRow.Cells["katId"].Value}"; //katId aus Datagrid dgvkat
        int deletedRows = dml(cmd);
        ....

SQLiteStudio 3.4.4

Visual Studio Community 2019

.net 4.7.3 mit c# V7.3

System.Data.SQLite 1.0.118

Zitat von Th69

Du mußt wohl nach jeder Verbindung zuerst PRAGMA foreign_keys = ON; absenden, s.a. SQLite Cascade Delete.

He, du kommst in mein Nachtgebet. Danke dir. Joerg

Man aktiviert essentielle Features in Datenbank, damit der Programmierer nicht ständig an zig Dinge denken muss um alles konsistent zu halten, und dann muss man aber in jedem Verbindungsaufbau explizit angeben dass ein derart wichtiges Feature auch wirklich aktiviert wird?

Verstehe ich da was falsch, oder ist das tatsächlich so schlecht wie es sich für mich anhört?

Ja, scheint wohl aus Kompatibilitätsgründen zu älteren Versionen so zu sein (auch wenn die SQLite-Entwickler es sich vorbehalten, es evtl. mal in Zukunft zu ändern), s.a. SQLite Foreign Key Support (s. "2. Enabling Foreign Key Support") - ich selber finde es auch sehr eigenartig.

SQLite ist auch nicht meine Lieblingsdatenbank (auch wenn es als lokale DB wenig Alternativen gibt) - insb. das File Locking Verhalten bei Multithreading DB-Operationen nervt.

Als Tipp am Rande:

In der DbContext-Ableitung kann man in der OnConfiguring-Methode (oder wenn man die DbContextOptions baut) einen Interceptor registrieren:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    optionsBuilder.AddInterceptors(new EnableForeignKeysConnectionInterceptor());
}

Und die Klasse dazu:

internal sealed class EnableForeignKeysConnectionInterceptor : DbConnectionInterceptor
{
    public override void ConnectionOpened(DbConnection connection, ConnectionEndEventData eventData)
    {
        // PRAGMA foreign_keys = ON
    }
    public override async Task ConnectionOpenedAsync(DbConnection connection, ConnectionEndEventData eventData, CancellationToken cancellationToken)
    {
        // PRAGMA foreign_keys = ON
    }
}

Dann passiert das bei jeder Connection automatisch.

NuGet Packages im Code auslesen
lock Alternative für async/await

Beim CleanCode zählen nicht die Regeln, sondern dass wir uns mit diesen Regeln befassen, selbst wenn wir sie nicht befolgen - hoffentlich nach reiflichen Überlegungen.