Sdílet prostřednictvím


Správa připojení

Tato stránka popisuje chování entity Framework s ohledem na předávání připojení k kontextu a funkcím Database.PřipojeníIon. Open() API.

Předávání Připojení ionů kontextu

Chování ef5 a starších verzí

Existují dva konstruktory, které přijímají připojení:

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

Tyto možnosti je možné použít, ale musíte obejít několik omezení:

  1. Pokud předáte otevřené připojení k některé z těchto možností, při prvním pokusu rozhraní o jeho použití InvalidOperationException je vyvolán, že nemůže znovu otevřít již otevřené připojení.
  2. Příznak contextOwns Připojení ion se interpretuje tak, aby znamenal, jestli se má podkladové připojení k úložišti likvidovat při odstranění kontextu. Bez ohledu na toto nastavení se ale připojení k úložišti vždy zavře při odstranění kontextu. Pokud tedy máte více než jeden DbContext se stejným připojením, podle toho, který kontext je uvolněn, nejprve připojení zavře (podobně pokud jste směšili existující ADO.NET připojení s DbContext, DbContext připojení vždy zavře, když je uvolněn).

První výše uvedené omezení je možné obejít předáním uzavřeného připojení a spuštěním kódu, který by ho otevřel po vytvoření všech kontextů:

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();
                }
            }
        }
    }
}

Druhé omezení jenom znamená, že se musíte vyhnout vyřazení jakéhokoli objektu DbContext, dokud nebudete připraveni na uzavření připojení.

Chování v EF6 a budoucích verzích

V EF6 a budoucích verzích dbContext má stejné dva konstruktory, ale už nevyžaduje, aby bylo připojení předáno konstruktoru při přijetí. Takže je to teď možné:

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();
            }
        }
    }
}

Také kontextOwns Připojení ion příznak nyní řídí, zda je připojení uzavřeno a uvolněno při odstranění DbContext. V předchozím příkladu tedy připojení není uzavřeno, když je kontext uvolněn (řádek 32), jako by byl v předchozích verzích EF, ale spíše když je samotné připojení uvolněno (řádek 40).

Samozřejmě, že DbContext je stále možné převzít kontrolu nad připojením (stačí nastavit kontextOwns Připojení ion na true nebo použít jeden z ostatních konstruktorů), pokud chcete.

Poznámka

Při použití transakcí s tímto novým modelem je potřeba vzít v úvahu některé další aspekty. Podrobnosti najdete v tématu Práce s transakcemi.

Databáze. Připojení ion. Open()

Chování ef5 a starších verzí

V EF5 a starších verzích existuje chyba, která objectContext.PřipojeníIon. Stav nebyl aktualizován tak, aby odrážel skutečný stav základního připojení úložiště. Pokud jste například spustili následující kód, můžete vrátit stav Uzavřeno , i když ve skutečnosti je základní připojení k úložišti otevřené.

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

Samostatně, pokud otevřete připojení k databázi voláním Database. Připojení ion. Open() se otevře až do příštího spuštění dotazu nebo volání čehokoli, co vyžaduje připojení k databázi (například SaveChanges()), ale po zavření základního připojení úložiště. Kontext se pak znovu otevře a znovu zavře připojení, kdykoli bude potřeba jiná operace databáze:

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();
            }
        }
    }
}

Chování v EF6 a budoucích verzích

Pro EF6 a budoucí verze jsme vzali přístup, že pokud se volající kód rozhodne otevřít připojení voláním kontextu. Databáze. Připojení ion. Open() pak má dobrý důvod k tomu a architektura předpokládá, že chce mít kontrolu nad otevřením a uzavřením připojení a už připojení automaticky nezavře.

Poznámka

To může potenciálně vést k připojením, která jsou otevřená po dlouhou dobu, takže je používejte opatrně.

Aktualizovali jsme také kód tak, aby ObjectContext. Připojení ion. Stav teď sleduje stav základního připojení správně.

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
        }
    }
}