共用方式為


連線管理

此頁面說明 Entity Framework 關於將連線 傳遞至 Database.連線離子。Open() API。

將連線傳遞至內容

EF5 和舊版的行為

有兩個接受連線的建構函式:

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

您可以使用這些限制,但您必須解決幾項限制:

  1. 如果您將開啟的連接傳遞給其中一個,則第一次嘗試使用它架構時,會擲回 InvalidOperationException,表示無法重新開啟已開啟的連接。
  2. coNtextOwns連線ion 旗標會解譯為表示在處置內容時,是否應該處置基礎存放區連線。 但是,不論該設定為何,處置內容時,存放區連接一律會關閉。 因此,如果您有一個以上的 DbCoNtext 與相同連接,但第一次處置的內容都會關閉連接(同樣地,如果您將現有的 ADO.NET 連接與 DbCoNtext 混合在一起,DbCoNtext 一律會在處置連接時關閉它)。

藉由傳遞已關閉的連線,並只執行會在建立所有內容之後開啟的程式碼,即可解決上述第一個限制:

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

第二個限制只是表示您必須避免處置任何 DbCoNtext 物件,直到您已準備好關閉連線為止。

EF6 和未來版本的行為

在 EF6 和未來的版本中,DbCoNtext 具有相同的兩個建構函式,但不再需要在收到建構函式時關閉傳遞給建構函式的連接。 因此,現在有可能:

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

此外,coNtextOwns連線ion 旗標現在也會控制當 DbCoNtext 處置時,連接是否同時關閉和處置。 因此,在上述範例中,當內容處置 (第 32 行) 時,不會關閉連線,因為它在舊版 EF 中,而是在處置連接本身時(第 40 行)。

當然,如果想要的話,DbCoNtext 仍然可以控制連線(只要將 coNtextOwns連線ion 設定為 true,或使用其中一個其他建構函式。

注意

搭配這個新模型使用交易時,有一些額外的考慮。 如需詳細資訊,請參閱 使用交易

資料庫。連線。Open()

EF5 和舊版的行為

在 EF5 和舊版中,有一個錯誤,讓 ObjectCoNtext.連線離子。狀態 未更新,以反映基礎存放區連線的真實狀態。 例如,如果您執行下列程式碼,即使基礎存放區連接是 Open ,還是可以傳 回狀態已 關閉

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

另外,如果您藉由呼叫 Database 來開啟資料庫連線。連線。Open() 將會開啟,直到您下次執行查詢或呼叫需要資料庫連接的任何專案時(例如 SaveChanges(),但之後基礎存放區連線將會關閉。 內容會在需要其他資料庫作業時重新開啟並重新關閉連線:

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

EF6 和未來版本的行為

針對 EF6 和未來的版本,我們已採用呼叫程式碼選擇呼叫內容來開啟連線的方法。資料庫。連線。Open() 然後它有充分的理由這樣做,架構會假設它想要控制連接開啟和關閉,而且不會再自動關閉連線。

注意

這可能會導致長時間開啟的連線,因此請小心使用。

我們也更新程式碼,讓 ObjectCoNtext。連線。狀態現在會正確追蹤基礎連線的狀態。

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