Laden...

EFCore Verbindungsprobleme und doppelte Einträge

Erstellt von schuppsl vor 3 Jahren Letzter Beitrag vor 3 Jahren 395 Views
S
schuppsl Themenstarter:in
789 Beiträge seit 2007
vor 3 Jahren
EFCore Verbindungsprobleme und doppelte Einträge

verwendetes Datenbanksystem: MSSQL

Hallo zusammen.

Eine Webanwendung speichert Formulardaten in einer Datenbank.
Es gibt also einen Senden-Button, welcher eine Backend-Methode zur Speicherung ausführt.

Per EFCore werden die Daten dann gespeichert.
Es scheint nun so, dass unser Datenbankserver ab und zu Probleme damit hat, Verbindungen aufzubauen.

Das daraus resultierende eigentliche Problem gestaltet sich aber folgendermaßen:

Absendebutton wird gedrückt, es wird versucht, die DB - Verbindung herzustellen, was aber in seltenen Fällen 5-8 Sekunden dauern kann.
Der User der Webanwendung wartet kurz und drückt dann nochmals auf Absenden, da es anscheinend beim ersten Mal nicht funktioniert hat.
Somit wird die "hängende" Methode erneut aufgerufen und EFCore versucht nochmals die Verbindung aufzubauen.

Irgendwie, irgendwo laufen also 2 Threads und beide "hängen" beim Verbindungsaufbau. (Using)
Geht es dann, so werden die Formulardaten doppelt in der DB gespeichert, da die Funktion zweimal aufgerufen wurde.

Der Verbindungsaufbau wird per Using gemacht:


using (con= new MyContext())
{
//
}

Und irgendwo hier hängt es dann.
Aus meiner Sicht ist das Problem, dass die Verbindung 2x aufgebaut und die Tabelle 2x in 2 verschiedene DbContext gelesen wird.
Deshalb schlagen Prüfungen, ob der Eintrag schon vorhanden ist (spezielle Kombination aus Key+ weitere Felder) fehl.

Es ist also ein Grundsatzproblem, was ich nicht verstanden habe.

Entprellung des Sendenbuttons und Hinweise in der Webanwendung- Ja.
Prüfung, ob der Eintrag schon in der DB existiert - Ja ( nützt hier aber nichts)
Klärung, warum die DB ab und zu die Verbindung so langsam aufbaut - Ja.

Damit kann man das Problem entschärfen oder umgehen, aber gelöst ist es grundsätzlich nicht.

Parallelitäts Erkennung nützt hier mMn nach auch nicht viel, da in die Tabelle nur geschrieben wird und derselbe Datensatz nicht von mehreren verändert wird.

Was ist hier also das Problem am Design, was habe ich nicht verstanden und wie hieße das "Zauberwort" für so einen Fall?

Ganz herzlichen Dank im Voraus.

16.807 Beiträge seit 2008
vor 3 Jahren

Irgendwie, irgendwo laufen also 2 Threads und beide "hängen" beim Verbindungsaufbau.

Ja, so funktionieren .NET Webanwendungen. Jeder Request ist (grundlegend) ein Thread.

Funktion zweimal aufgerufen wurde.

Methode.

Der Verbindungsaufbau wird per Using gemacht:

Was generell ein Anti-Pattern darstellt und den Code untestbar macht.
Mit dem Problem hat das nichts zutun.

Aus meiner Sicht ist das Problem, dass die Verbindung 2x aufgebaut und die Tabelle 2x in 2 verschiedene DbContext gelesen wird.

Es ist gut, dass hier zwei Contexte verwendet werden, weil der Context nicht Thread-Safe ist und daher pro Request ein Context erstellt werden muss.

Deshalb schlagen Prüfungen, ob der Eintrag schon vorhanden ist

Naja, Du prüfst offenbar halt nur Client-seitig.

Prüfung, ob der Eintrag schon in der DB existiert - Ja ( nützt hier aber nichts)

Doch, der würde was bringen, wenn es in der Datenbank erfolgt.
Du prüfst aber eben innerhalb einer potentiellen Race Condition: natürlich ist das dann nicht stabil.

Damit kann man das Problem entschärfen oder umgehen, aber gelöst ist es grundsätzlich nicht.

Das is generell kein Problem mit EF, sondern das ist ein Problem mit jeder Datenbank-Interaktion in jeder Umgebung.
SQL INSERT but avoid duplicates

Bei Dir tritt es eben häufiger auf, weil der User durch eine schlechte Performance der Anwendung bewusst das Formular erneut absendet und daher erst die Situation aufkommt, dass die Aktion zwei mal erfolgt.
Ansonsten würde das - auch wenn das grundlegende Potential weiter bestehen würde - kaum auftreten.

S
schuppsl Themenstarter:in
789 Beiträge seit 2007
vor 3 Jahren

Ganz lieben Dank.

Naja, Du prüfst offenbar halt nur Client-seitig.

Doch, der würde was bringen, wenn es in der Datenbank erfolgt.
Du prüfst aber eben innerhalb einer potentiellen Race Condition: natürlich ist das dann nicht stabil.

Die Prüfung auf vorhandenen Eintrag wird innerhalb der Using-Anweisung gemacht.

Doch, der würde was bringen, wenn es in der Datenbank erfolgt.
Du prüfst aber eben innerhalb einer potentiellen Race Condition: natürlich ist das dann nicht stabil.

So ist es.

Prüfung in der Datenbank? Interessant.

Also ist die Entprellung des Absendebuttons der beste Weg um das Problem zu minimieren.

16.807 Beiträge seit 2008
vor 3 Jahren

Also ist die Entprellung des Absendebuttons der beste Weg um das Problem zu minimieren.

Als "beste" würde ich das sicherlich nicht bezeichnen, aber wäre vermutlich ein Workaround. "Beste" wäre es dort zu verhindern, wo es auftritt: und das ist die Datenbank.

S
schuppsl Themenstarter:in
789 Beiträge seit 2007
vor 3 Jahren

Und wie könnte diese Lösung ungefähr aussehen?
Stored Procedure, die das vorab prüft?

16.807 Beiträge seit 2008
vor 3 Jahren

Hab Dir den Link SQL INSERT but avoid duplicates nicht umsonst gegeben.
Da stehts drin und ist selbst nach 11 Jahren immer noch eine adäquate Lösung.

S
schuppsl Themenstarter:in
789 Beiträge seit 2007
vor 3 Jahren

Ganz herzlichen Dank!