Verwenden von TransaktionenUsing Transactions

Transaktionen können mehrere Datenbankvorgänge in eine atomare Weise verarbeitet werden.Transactions allow several database operations to be processed in an atomic manner. Wenn die Transaktion ein Commit ausgeführt wird, werden alle Vorgänge erfolgreich auf die Datenbank angewendet.If the transaction is committed, all of the operations are successfully applied to the database. Wenn die Transaktion ein Rollback ausgeführt wird, werden keiner der Vorgänge auf die Datenbank angewendet.If the transaction is rolled back, none of the operations are applied to the database.

Tipp

Sie können anzeigen, dass dieser Artikel Beispiel auf GitHub.You can view this article's sample on GitHub.

Standardverhalten für die TransaktionDefault transaction behavior

Standardmäßig, wenn der Anbieter Transaktionen unterstützt alle Änderungen in einem einzigen Aufruf SaveChanges() in einer Transaktion angewendet werden.By default, if the database provider supports transactions, all changes in a single call to SaveChanges() are applied in a transaction. Wenn einer der Änderungen fehlschlägt, wird ein Rollback für die Transaktion, und keine der Änderungen auf die Datenbank angewendet werden.If any of the changes fail, then the transaction is rolled back and none of the changes are applied to the database. Dies bedeutet, dass SaveChanges() wird sichergestellt, dass entweder vollständig erfolgreich ausgeführt werden, oder lassen Sie die Datenbank, die unverändert bleiben sollen, wenn ein Fehler auftritt.This means that SaveChanges() is guaranteed to either completely succeed, or leave the database unmodified if an error occurs.

Für die meisten Anwendungen ist dieses Standardverhalten ausreichend.For most applications, this default behavior is sufficient. Transaktionen sollten nur manuell gesteuert werden, wenn die Anforderungen an Ihre Anwendung erforderlichen aufgefasst.You should only manually control transactions if your application requirements deem it necessary.

Steuern von TransaktionenControlling transactions

Sie können die DbContext.Database -API zum Starten der commit und Rollback-Transaktionen.You can use the DbContext.Database API to begin, commit, and rollback transactions. Das folgende Beispiel zeigt zwei SaveChanges() Vorgänge und eine LINQ-Abfrage in einer einzelnen Transaktion ausgeführt wird.The following example shows two SaveChanges() operations and a LINQ query being executed in a single transaction.

Nicht alle Datenbankanbieter unterstützen Transaktionen.Not all database providers support transactions. Einige Anbieter auslösen oder ohne-Op Wenn Transaktion APIs aufgerufen werden.Some providers may throw or no-op when transaction APIs are called.

        using (var context = new BloggingContext())
        {
            using (var transaction = context.Database.BeginTransaction())
            {
                try
                {
                    context.Blogs.Add(new Blog { Url = "http://blogs.msdn.com/dotnet" });
                    context.SaveChanges();

                    context.Blogs.Add(new Blog { Url = "http://blogs.msdn.com/visualstudio" });
                    context.SaveChanges();

                    var blogs = context.Blogs
                        .OrderBy(b => b.Url)
                        .ToList();

                    // Commit transaction if all commands succeed, transaction will auto-rollback
                    // when disposed if either commands fails
                    transaction.Commit();
                }
                catch (Exception)
                {
                    // TODO: Handle failure
                }
            }
        }

Cross-Kontexttransaktion (nur bei relationalen Datenbanken)Cross-context transaction (relational databases only)

Sie können auch eine Transaktion über mehrere Instanzen von Kontext freigeben.You can also share a transaction across multiple context instances. Diese Funktion ist nur verfügbar, wenn einen relationale Datenbank-Anbieter verwenden, da es erfordert, dass die Verwendung von DbTransaction und DbConnection, die speziell für relationale Datenbanken sind.This functionality is only available when using a relational database provider because it requires the use of DbTransaction and DbConnection, which are specific to relational databases.

Um eine Transaktion gemeinsam nutzen, müssen die Kontexte verwenden beide eine DbConnection und ein DbTransaction.To share a transaction, the contexts must share both a DbConnection and a DbTransaction.

Lassen Sie Verbindung mit extern bereitgestellt werden zuAllow connection to be externally provided

Freigeben einer DbConnection erfordert die Möglichkeit, eine Verbindung in einem Kontext übergeben wird, wenn es zu erstellen.Sharing a DbConnection requires the ability to pass a connection into a context when constructing it.

Die einfachste Möglichkeit zum Zulassen DbConnection extern bereitgestellt werden, ist, Beenden der Verwendung der DbContext.OnConfiguring Methode so extern erstellen und konfigurieren den Kontext DbContextOptions und an den Kontext Konstruktor zu übergeben.The easiest way to allow DbConnection to be externally provided, is to stop using the DbContext.OnConfiguring method to configure the context and externally create DbContextOptions and pass them to the context constructor.

Tipp

DbContextOptionsBuilderist die API im verwendet haben DbContext.OnConfiguring um den Kontext zu konfigurieren, Sie sind nun damit extern erstellen mit DbContextOptions.DbContextOptionsBuilder is the API you used in DbContext.OnConfiguring to configure the context, you are now going to use it externally to create DbContextOptions.

    public class BloggingContext : DbContext
    {
        public BloggingContext(DbContextOptions<BloggingContext> options)
            : base(options)
        { }

        public DbSet<Blog> Blogs { get; set; }
    }

Eine Alternative besteht darin, die weitere Verwendung DbContext.OnConfiguring, akzeptieren jedoch eine DbConnection , gespeichert und dann im verwendet DbContext.OnConfiguring.An alternative is to keep using DbContext.OnConfiguring, but accept a DbConnection that is saved and then used in DbContext.OnConfiguring.

public class BloggingContext : DbContext
{
    private DbConnection _connection;

    public BloggingContext(DbConnection connection)
    {
      _connection = connection;
    }

    public DbSet<Blog> Blogs { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer(_connection);
    }
}

Freigabe-Verbindung und der TransaktionsstatusShare connection and transaction

Sie können nun mehrere Kontext Instanzen erstellen, die die gleiche Verbindung verwenden.You can now create multiple context instances that share the same connection. Verwenden Sie dann die DbContext.Database.UseTransaction(DbTransaction) -API, um beide Kontexte in derselben Transaktion eintragen.Then use the DbContext.Database.UseTransaction(DbTransaction) API to enlist both contexts in the same transaction.

        var options = new DbContextOptionsBuilder<BloggingContext>()
            .UseSqlServer(new SqlConnection(connectionString))
            .Options;

        using (var context1 = new BloggingContext(options))
        {
            using (var transaction = context1.Database.BeginTransaction())
            {
                try
                {
                    context1.Blogs.Add(new Blog { Url = "http://blogs.msdn.com/dotnet" });
                    context1.SaveChanges();

                    using (var context2 = new BloggingContext(options))
                    {
                        context2.Database.UseTransaction(transaction.GetDbTransaction());

                        var blogs = context2.Blogs
                            .OrderBy(b => b.Url)
                            .ToList();
                    }

                    // Commit transaction if all commands succeed, transaction will auto-rollback
                    // when disposed if either commands fails
                    transaction.Commit();
                }
                catch (Exception)
                {
                    // TODO: Handle failure
                }
            }
        }

Verwenden von externen DbTransactions (nur bei relationalen Datenbanken)Using external DbTransactions (relational databases only)

Wenn Sie mehrere datenzugriffstechnologien Zugriff auf eine relationale Datenbank verwenden, empfiehlt es sich, eine Transaktion zwischen Operationen, die von diesen anderen Technologien gemeinsam nutzen.If you are using multiple data access technologies to access a relational database, you may want to share a transaction between operations performed by these different technologies.

Im folgenden Beispiel wird gezeigt, wie ein ADO.NET SqlClient-Vorgang und ein Entity Framework Core-Vorgang in derselben Transaktion ausgeführt.The following example, shows how to perform an ADO.NET SqlClient operation and an Entity Framework Core operation in the same transaction.

        var connection = new SqlConnection(connectionString);
        connection.Open();

        using (var transaction = connection.BeginTransaction())
        {
            try
            {
                // Run raw ADO.NET command in the transaction
                var command = connection.CreateCommand();
                command.Transaction = transaction;
                command.CommandText = "DELETE FROM dbo.Blogs";
                command.ExecuteNonQuery();

                // Run an EF Core command in the transaction
                var options = new DbContextOptionsBuilder<BloggingContext>()
                    .UseSqlServer(connection)
                    .Options;

                using (var context = new BloggingContext(options))
                {
                    context.Database.UseTransaction(transaction);
                    context.Blogs.Add(new Blog { Url = "http://blogs.msdn.com/dotnet" });
                    context.SaveChanges();
                }

                // Commit transaction if all commands succeed, transaction will auto-rollback
                // when disposed if either commands fails
                transaction.Commit();
            }
            catch (System.Exception)
            {
                // TODO: Handle failure
            }