Freigabe einer Verbindung und einer Transaktion in EF über mehrere Kontexte (UnintentionalCodeFirstException)

8

Die vorherige Version und die Frage werden unten als zusätzlicher Kontext bereitgestellt. Die verbesserte Problemformulierung und -frage könnte wie folgt aussehen:

  • Wie teilt man eine Transaktion zwischen mehreren Kontexten in der Datenbank EF 6.1.0 zuerst und .NET 4.5.2 ohne eine verteilte Transaktion?

Dafür sieht es so aus, als müsste ich eine Verbindung zwischen den verschiedenen Kontexten teilen, aber die Codebeispiele und Tutorials, die ich bisher gesehen habe, waren nicht so erfolgreich. Das Problem sieht so aus, als schwebe man herum, wie man eine funktionierende Kombination aus einem Verbindungsobjekt und Transaktionsobjekttypen definiert, so dass Metadaten der ersten Datenbank der EF-Datenbank auch beim Konstruieren der Objektkontexte erstellt und gefunden werden.

Das heißt, ich möchte etwas tun, was in den EF 6.n Tutorials beschrieben wurde hier . Ein Beispielcode könnte

sein %Vor%

In den Beispielen gibt es auch andere Methoden, wie man eine geteilte Verbindung und eine Transaktion erstellt, aber wie geschrieben scheint der Täter zu sein, wenn, sagen wir, die connectiong-Zeichenfolge in (die "..." Teil) das vorherige Snippet als dummyContext.Database.Connection.ConnectionString Ich bekomme nur eine Ausnahme.

Ich bin mir nicht sicher, ob ich gerade die falschen Quellen lese oder ob etwas anderes in meinem Code nicht stimmt, wenn ich versuche, eine Transaktion über mehrere EF-Kontexte hinweg zu teilen. Wie könnte es gemacht werden?

Ich habe schon einige andere SO-Posts gelesen (zB diese ) und einige Tutorials . Sie haben nicht geholfen.

Ich habe ein merkwürdiges Problem darin, dass es aussieht, dass ich die Konstruktorüberladungen nicht wie in anderen Tutorials und Posts definiert habe. Das heißt, unter Verwendung des verknüpften Tutorial-Links kann ich new BloggingContext(conn, contextOwnsConnection: false)) nicht schreiben und eine gemeinsam genutzte Verbindung und eine externe Transaktion verwenden.

Wenn ich dann

schreibe %Vor%

und benutze es wie in den Tutorials, bekomme ich eine Ausnahme von der folgenden Zeile aus dem folgenden T4 Vorlage generierten Code

%Vor%

Ich verwende .NET 4.5.2 und EF 6.1.0. Ich habe das edmx aus einer vorhandenen Datenbank erstellt und den Code von dort generiert. In dieser speziellen Situation verwende ich Task Parallel Threads, um Dutzende von SQL Server Master Data Services zu laden Staging-Tabellen (ja, ein großes Modell) und die zugehörigen Prozeduren aufzurufen (jeweils vom MDS pro Tabelle bereitgestellt). MDS verfügt über eine eigene Kompensationslogik, falls das Staging für einige der Tabellen fehlschlägt. Das Zurücksetzen einer Transaktion sollte jedoch ebenfalls möglich sein. Es sieht einfach so aus, als hätte ich ein (seltsames) Problem mit meiner EF.

& lt; Nachtrag: Steve schlug vor, gerade TransactionScope zu verwenden. Ohne eine gemeinsame Verbindung, die eine verteilte Transaktion erfordern würde, die ich nicht wählen kann. Dann, wenn ich versuche, eine gemeinsame Verbindung für die Kontexte bereitzustellen (einige Optionen in den Tutorials gezeigt, ein here Ich habe das Problem" fehlende Konstruktoren ". Wenn ich einen definiere, bekomme ich die Ausnahme, die ich im Code verweise. Alles in allem fühlt sich das merkwürdig an. Vielleicht ist etwas falsch daran, wie ich gehe über das Erzeugen der DbContext und verwandter Klassen.

& lt; Hinweis 1: Es sieht so aus, als ob die Ursache in diesem Blogpost von Arthur (vom EF-Entwicklerteam) Verwenden Sie Code First nicht versehentlich . Das heißt, in der ersten Entwicklung der Datenbank sucht das Framework nach den klassenrelationalen Zuordnungen, wie sie in der Verbindungszeichenfolge definiert sind. Etwas fischiges in meinem Verbindungsstring das ist ..?

    
Veksi 29.05.2014, 15:56
quelle

2 Antworten

2

Aufgrund des Verbindungspools führt die Verwendung mehrerer EF DbContext , die genau die gleiche Verbindungszeichenfolge verwenden, unter demselben Transaktionsbereich normalerweise nicht zu einer DTC-Eskalation (es sei denn, Sie haben das Pooling in der Verbindungszeichenfolge deaktiviert), da die gleiche Verbindung besteht für beide wiederverwendet (aus dem Pool). Wie auch immer, Sie können die gleiche Verbindung in Ihrem Fall wie folgt verwenden (ich nehme an, Sie haben bereits einen Konstruktor hinzugefügt, der DbConnection akzeptiert und ein Flag, das anzeigt, ob der Kontext eine Verbindung hat):

%Vor%

Dies funktioniert und wirft UnintentionalCodeFirstExce‌​ption nicht, weil Sie EntityConnection übergeben haben. Diese Verbindung enthält Informationen zu EDMX-Metadaten, die von der Datenbank zuerst benötigt werden. Wenn Sie plain SqlConnection übergeben - EF hat keine Ahnung, wo nach Metadaten gesucht werden soll und es nicht einmal sollte danach suchen - also nimmt es sofort an, dass Sie zuerst Code machen.

Beachten Sie, dass ich die EF-Verbindungszeichenfolge im obigen Code übergebe. Wenn Sie eine einfache SqlConnection haben, die Sie auf andere Weise erhalten haben, außerhalb von EF, funktioniert das nicht, da die Verbindung string benötigt wird. Aber es ist immer noch möglich, weil EntityConnection einen Konstruktor hat, der plain DbConnection akzeptiert. Allerdings sollten Sie dann selbst auf Metadaten verweisen. Wenn Sie daran interessiert sind, kann ich ein Codebeispiel dafür bereitstellen.

Um zu überprüfen, ob Sie tatsächlich eine Eskalation in allen Fällen verhindern - deaktivieren Sie das Pooling ( Pooling=false in der Verbindungszeichenfolge) und stoppen Sie den DTC-Dienst, und führen Sie diesen Code aus - er sollte ordnungsgemäß funktionieren. Führen Sie dann einen anderen Code aus, der nicht die gleiche Verbindung hat, und Sie sollten den Fehler beobachten, der darauf hinweist, dass eine Eskalation passieren würde, aber der Dienst nicht verfügbar ist.

    
Evk 17.11.2017 21:17
quelle
1

Haben Sie versucht, die Aufrufe in einen Transaktionsbereich umzubrechen?

%Vor%     
Steve Stokes 29.05.2014 16:22
quelle

Tags und Links