VerbindungsverwaltungConnection management

Auf dieser Seite wird das Verhalten von Entity Framework in Bezug auf das Übergeben von Verbindungen mit dem Kontext und die Funktionalität der Database. Connection. Open () -API beschrieben.This page describes the behavior of Entity Framework with regard to passing connections to the context and the functionality of the Database.Connection.Open() API.

Übergeben von Verbindungen an den KontextPassing Connections to the Context

Verhalten für EF5 und frühere VersionenBehavior for EF5 and earlier versions

Es gibt zwei Konstruktoren, die Verbindungen akzeptieren:There are two constructors which accept connections:

public DbContext(DbConnection existingConnection, bool contextOwnsConnection)
public DbContext(DbConnection existingConnection, DbCompiledModel model, bool contextOwnsConnection)

Es ist möglich, diese zu verwenden, aber Sie müssen einige Einschränkungen umgehen:It is possible to use these but you have to work around a couple of limitations:

  1. Wenn Sie eine offene Verbindung an eine dieser Optionen übergeben, wird das erste Mal, wenn das Framework versucht, es zu verwenden, eine InvalidOperationException ausgelöst, die besagt, dass eine bereits geöffnete Verbindung nicht erneut geöffnet werden kann.If you pass an open connection to either of these then the first time the framework attempts to use it an InvalidOperationException is thrown saying it cannot re-open an already open connection.
  2. Das contextownsconnection-Flag gibt an, ob die zugrunde liegende Speicher Verbindung verworfen werden soll, wenn der Kontext verworfen wird.The contextOwnsConnection flag is interpreted to mean whether or not the underlying store connection should be disposed when the context is disposed. Unabhängig von dieser Einstellung wird die Speicher Verbindung jedoch immer geschlossen, wenn der Kontext verworfen wird.But, regardless of that setting, the store connection is always closed when the context is disposed. Wenn Sie also über mehr als einen dbcontext mit derselben Verbindung verfügen, wenn der Kontext zuerst verworfen wird, wird die Verbindung geschlossen (ähnlich, wenn Sie eine vorhandene ADO.NET-Verbindung mit einem dbcontext gemischt haben, schließt dbcontext die Verbindung immer, wenn Sie verworfen wird).So if you have more than one DbContext with the same connection whichever context is disposed first will close the connection (similarly if you have mixed an existing ADO.NET connection with a DbContext, DbContext will always close the connection when it is disposed).

Es ist möglich, die oben beschriebene Einschränkung zu umgehen, indem Sie eine geschlossene Verbindung übergibt und nur Code ausführt, der Sie nach der Erstellung aller Kontexte öffnet:It is possible to work around the first limitation above by passing a closed connection and only executing code that would open it once all contexts have been created:

using System.Collections.Generic;
using System.Data.Common;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Data.EntityClient;
using System.Linq;

namespace ConnectionManagementExamples
{
    class ConnectionManagementExampleEF5
    {         
        public static void TwoDbContextsOneConnection()
        {
            using (var context1 = new BloggingContext())
            {
                var conn =
                    ((EntityConnection)  
                        ((IObjectContextAdapter)context1).ObjectContext.Connection)  
                            .StoreConnection;

                using (var context2 = new BloggingContext(conn, contextOwnsConnection: false))
                {
                    context2.Database.ExecuteSqlCommand(
                        @"UPDATE Blogs SET Rating = 5" +
                        " WHERE Name LIKE '%Entity Framework%'");

                    var query = context1.Posts.Where(p => p.Blog.Rating > 5);
                    foreach (var post in query)
                    {
                        post.Title += "[Cool Blog]";
                    }
                    context1.SaveChanges();
                }
            }
        }
    }
}

Die zweite Einschränkung bedeutet lediglich, dass Sie Ihre dbcontext-Objekte verwerfen müssen, bis Sie bereit sind, die Verbindung zu schließen.The second limitation just means you need to refrain from disposing any of your DbContext objects until you are ready for the connection to be closed.

Verhalten in EF6 und zukünftigen VersionenBehavior in EF6 and future versions

In EF6 und zukünftigen Versionen hat dbcontext die gleichen beiden Konstruktoren, erfordert jedoch nicht mehr, dass die an den Konstruktor weiter gegebene Verbindung geschlossen wird, wenn Sie empfangen wird.In EF6 and future versions the DbContext has the same two constructors but no longer requires that the connection passed to the constructor be closed when it is received. Dies ist nun möglich:So this is now possible:

using System.Collections.Generic;
using System.Data.Entity;
using System.Data.SqlClient;
using System.Linq;
using System.Transactions;

namespace ConnectionManagementExamples
{
    class ConnectionManagementExample
    {
        public static void PassingAnOpenConnection()
        {
            using (var conn = new SqlConnection("{connectionString}"))
            {
                conn.Open();

                var sqlCommand = new SqlCommand();
                sqlCommand.Connection = conn;
                sqlCommand.CommandText =
                    @"UPDATE Blogs SET Rating = 5" +
                     " WHERE Name LIKE '%Entity Framework%'";
                sqlCommand.ExecuteNonQuery();

                using (var context = new BloggingContext(conn, contextOwnsConnection: false))
                {
                    var query = context.Posts.Where(p => p.Blog.Rating > 5);
                    foreach (var post in query)
                    {
                        post.Title += "[Cool Blog]";
                    }
                    context.SaveChanges();
                }

                var sqlCommand2 = new SqlCommand();
                sqlCommand2.Connection = conn;
                sqlCommand2.CommandText =
                    @"UPDATE Blogs SET Rating = 7" +
                     " WHERE Name LIKE '%Entity Framework Rocks%'";
                sqlCommand2.ExecuteNonQuery();
            }
        }
    }
}

Außerdem steuert das contextownsconnection-Flag nun, ob die Verbindung geschlossen und freigegeben wird, wenn der dbcontext verworfen wird.Also the contextOwnsConnection flag now controls whether or not the connection is both closed and disposed when the DbContext is disposed. Im obigen Beispiel wird die Verbindung nicht geschlossen, wenn der kontextfrei gegeben wird (Zeile 32), wie es in früheren Versionen von EF der Fall war, sondern wenn die Verbindung selbst verworfen wurde (Zeile 40).So in the above example the connection is not closed when the context is disposed (line 32) as it would have been in previous versions of EF, but rather when the connection itself is disposed (line 40).

Natürlich kann dbcontext weiterhin die Kontrolle über die Verbindung übernehmen (legen Sie einfach "contextownsconnection" auf "true" fest, oder verwenden Sie einen der anderen Konstruktoren), wenn Sie dies wünschen.Of course it is still possible for the DbContext to take control of the connection (just set contextOwnsConnection to true or use one of the other constructors) if you so wish.

Hinweis

Bei der Verwendung von Transaktionen mit diesem neuen Modell sind einige weitere Überlegungen zu beachten.There are some additional considerations when using transactions with this new model. Weitere Informationen finden Sie unter Arbeiten mit Transaktionen.For details see Working with Transactions.

Database. Connection. Open ()Database.Connection.Open()

Verhalten für EF5 und frühere VersionenBehavior for EF5 and earlier versions

In EF5 und früheren Versionen ist ein Fehler aufgetreten, so dass ObjectContext. Connection. State nicht aktualisiert wurde, um den tatsächlichen Status der zugrunde liegenden Speicher Verbindung widerzuspiegeln.In EF5 and earlier versions there is a bug such that the ObjectContext.Connection.State was not updated to reflect the true state of the underlying store connection. Wenn Sie z. b. den folgenden Code ausgeführt haben, können Sie den Status " geschlossen " zurückgeben, obwohl die zugrunde liegende Speicher Verbindung tatsächlich geöffnetist.For example, if you executed the following code you can be returned the status Closed even though in fact the underlying store connection is Open.

((IObjectContextAdapter)context).ObjectContext.Connection.State

Wenn Sie die Datenbankverbindung öffnen, indem Sie Database. Connection. Open () aufrufen, wird Sie separat geöffnet, bis Sie das nächste Mal eine Abfrage ausführen oder etwas aufrufen, das eine Datenbankverbindung erfordert (z. b. SaveChanges ()), aber danach wird die zugrunde liegende Speicher Verbindung geschlossen.Separately, if you open the database connection by calling Database.Connection.Open() it will be open until the next time you execute a query or call anything which requires a database connection (for example, SaveChanges()) but after that the underlying store connection will be closed. Der Kontext wird dann erneut geöffnet, und die Verbindung wird immer wieder geschlossen, wenn ein anderer Daten Bank Vorgang erforderlich ist:The context will then re-open and re-close the connection any time another database operation is required:

using System;
using System.Data;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Data.EntityClient;

namespace ConnectionManagementExamples
{
    public class DatabaseOpenConnectionBehaviorEF5
    {
        public static void DatabaseOpenConnectionBehavior()
        {
            using (var context = new BloggingContext())
            {
                // At this point the underlying store connection is closed

                context.Database.Connection.Open();

                // Now the underlying store connection is open  
                // (though ObjectContext.Connection.State will report closed)

                var blog = new Blog { /* Blog’s properties */ };
                context.Blogs.Add(blog);

                // The underlying store connection is still open  

                context.SaveChanges();

                // After SaveChanges() the underlying store connection is closed  
                // Each SaveChanges() / query etc now opens and immediately closes
                // the underlying store connection

                blog = new Blog { /* Blog’s properties */ };
                context.Blogs.Add(blog);
                context.SaveChanges();
            }
        }
    }
}

Verhalten in EF6 und zukünftigen VersionenBehavior in EF6 and future versions

Bei EF6 und zukünftigen Versionen haben wir den Ansatz herangezogen, wenn der aufrufenden Code die Verbindung durch Aufrufen von Context öffnet. Database. Connection. Open () hat dann einen guten Grund dafür, und das Framework geht davon aus, dass es die Kontrolle über das Öffnen und Schließen der Verbindung wünscht und die Verbindung nicht mehr automatisch schließt.For EF6 and future versions we have taken the approach that if the calling code chooses to open the connection by calling context.Database.Connection.Open() then it has a good reason for doing so and the framework will assume that it wants control over opening and closing of the connection and will no longer close the connection automatically.

Hinweis

Dies kann potenziell zu Verbindungen führen, die für einen längeren Zeitraum geöffnet sind. verwenden Sie daher mit Bedacht.This can potentially lead to connections which are open for a long time so use with care.

Wir haben auch den Code so aktualisiert, dass ObjectContext. Connection. State nun den Status der zugrunde liegenden Verbindung korrekt nachverfolgt.We also updated the code so that ObjectContext.Connection.State now keeps track of the state of the underlying connection correctly.

using System;
using System.Data;
using System.Data.Entity;
using System.Data.Entity.Core.EntityClient;
using System.Data.Entity.Infrastructure;

namespace ConnectionManagementExamples
{
    internal class DatabaseOpenConnectionBehaviorEF6
    {
        public static void DatabaseOpenConnectionBehavior()
        {
            using (var context = new BloggingContext())
            {
                // At this point the underlying store connection is closed

                context.Database.Connection.Open();

                // Now the underlying store connection is open and the
                // ObjectContext.Connection.State correctly reports open too

                var blog = new Blog { /* Blog’s properties */ };
                context.Blogs.Add(blog);
                context.SaveChanges();

                // The underlying store connection remains open for the next operation  

                blog = new Blog { /* Blog’s properties */ };
                context.Blogs.Add(blog);
                context.SaveChanges();

                // The underlying store connection is still open

           } // The context is disposed – so now the underlying store connection is closed
        }
    }
}