Wenn Sie einen Code wie diesen haben:
Something something = new Something();
BlahEntities b = new BlahEntities()
b.AddToSomethingSet(something);
b.SaveChanges();
Wie führt man diesen Zusatz innerhalb einer Transaktion aus?
Wenn Sie einen Code wie diesen haben:
Something something = new Something();
BlahEntities b = new BlahEntities()
b.AddToSomethingSet(something);
b.SaveChanges();
Wie führt man diesen Zusatz innerhalb einer Transaktion aus?
Der ObjectContext verfügt über eine Verbindungseigenschaft, die Sie zur Verwaltung von Transaktionen verwenden können.
using (var context = new BlahEntities())
using (var tx = context.BeginTransaction())
{
// do db stuff here...
tx.Commit();
}
Im Falle einer Ausnahme wird die Transaktion rückgängig gemacht. Da der Aufruf von BeginTransaction() eine offene Verbindung erfordert, ist es sinnvoll, den Aufruf von BeginTransaction möglicherweise in eine Erweiterungsmethode zu verpacken.
public static DbTransaction BeginTransaction(this ObjectContext context)
{
if (context.Connection.State != ConnectionState.Open)
{
context.Connection.Open();
}
return context.Connection.BeginTransaction();
}
Ein Szenario, in dem dieser Ansatz meiner Meinung nach gegenüber TransactionScope nützlich sein könnte, ist, wenn Sie auf zwei Datenquellen zugreifen müssen und nur für eine der Verbindungen Transaktionskontrolle benötigen. Ich denke, dass TransactionScope in diesem Fall zu einer verteilten Transaktion übergehen wird, die möglicherweise nicht erforderlich ist.
Dies funktioniert in EF4.1 nicht mehr. Sie müssen Folgendes aufrufen context.Connection.BeginTransaction
.
@Mikey Cee, es funktioniert, du hast nicht bis zum Ende gelesen - Kim hat die Erweiterungsmethode eingeführt. Kim -- du bist der Mann!!! Du hast mir sehr geholfen, herzlichen Dank.
@Kim, vielen Dank für die Unterstützung, das war wirklich hilfreich. Ich möchte jedoch wissen, ob context.Connection.BeginTransaction() zu einer verteilten Transaktion (MSDTC) eskaliert? Ich möchte MSDTC vermeiden, ist das möglich?
Sie können Ihren Code innerhalb eines Transaktionsbereichs platzieren
using(TransactionScope scope = new TransactionScope())
{
// Your code
scope.Complete(); // To commit.
}
TransactionScope befindet sich im System.Transactions-Namensraum, der sich in der gleichnamigen Assembly befindet (die Sie möglicherweise manuell zu Ihrem Projekt hinzufügen müssen).
Wie ist dies möglich - woher weiß der TransactionScope über den EF-Kontext Bescheid, und/oder umgekehrt?
TransActionScope ist eine Art Wrapper für alles, was Sie tun können: msdn.microsoft.com/de-us/library/
Seien Sie vorsichtig mit TransactionScope. Es führt Abhängigkeiten von MS DTC ein, die mühsam zu konfigurieren sind und einen hohen Leistungsverlust mit sich bringen. Sobald Sie mehr als eine Transaktion innerhalb von TransactionScope haben, wird eine verteilte Transaktion initiiert. Es handelt sich dann nicht mehr nur um eine einfache DbTransaction, die auf dem verwendeten Provider läuft. Wenn Sie einen anderen Datenbankanbieter als Sql Server verwenden, ist es außerdem wahrscheinlich, dass dieser keine verteilten Transaktionen unterstützt...
Ich weiß, dass für LINQ to SQL, der Datenkontext eine Transaktion für SubmitChanges() erstellt, wenn es keine vorhandene umgebende Transaktion gibt (TransactionScope ist eine "umgebende" Transaktion). Ich habe nicht gesehen, dass dies für LINQ to Entities dokumentiert ist, aber ich habe Verhalten gesehen, das darauf hindeutet, dass es auch für Entity Framework gilt.
Solange Sie also ein SubmitChanges() (L2SQL) oder SaveChanges() (Linq to Entities) für alle damit zusammenhängenden Änderungen verwenden, sollten Sie ohne TransactionScope auskommen. Sie brauchen einen TransactionScope, wenn
Ich habe Probleme mit verschachtelten TransactionScopes gehabt. Sie sollen funktionieren, und einfache Testfälle funktionieren, aber wenn ich in den Produktionscode gehe, scheint die "innere" Transaktion dasselbe Objekt zu sein wie die äußere Transaktion. Zu den Symptomen gehören Fehler, die entweder lauten "transaction committed, you can't use this transaction any more" oder "this transaction object has already been disposed". Die Fehler treten in der äußeren Transaktion auf, nachdem die innere Transaktion ihre Arbeit erledigt hat.
Danke cyloncat für die ausführliche Beschreibung. Was ich mache, ist, den Datensatz zu erstellen, zu speichern und eine Datei mit der ID des Datensatzes zu erstellen. Erst wenn die Erstellung der Dateien erfolgreich war, gebe ich die Transaktion frei. Macht das Sinn?
using System.Transactions;
using (TransactionScope scope = new TransactionScope())
{
try
{
using(DataContext contextObject = new DataContext(ConnectionString))
{
contextObject.Connection.Open();
// First SaveChange method.
contextObject.SaveChanges();
// Second SaveChange method.
contextObject.SaveChanges();
//--continue to nth save changes
// If all execution successful
scope.Complete();
}
}
catch(Exception ex)
{
// If any exception is caught, roll back the entire transaction and end the scope.
scope.Dispose();
}
finally
{
// Close the opened connection
if (contextObject.Connection.State == ConnectionState.Open)
{
contextObject.Connection.Close();
}
}
}
Ausführliche Erläuterungen finden Sie unter folgendem Link https://msdn.microsoft.com/en-us/data/dn456843.aspx
In allen Versionen von Entity Framework wird bei jeder Ausführung von SaveChanges() zum Einfügen, Aktualisieren oder Löschen in der Datenbank diese Operation in eine Transaktion verpackt. Diese Transaktion dauert nur lange genug, um die Operation auszuführen und wird dann beendet. Wenn Sie eine weitere solche Operation ausführen, wird eine neue Transaktion gestartet. Für die neueste Entity Framework Version: 6.0 +
Lesen Sie hier mehr: EntityFramework und Transaktion
CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.