連線管理
此頁面說明 Entity Framework 關於將連線 傳遞至 Database.連線離子。Open() API。
將連線傳遞至內容
EF5 和舊版的行為
有兩個接受連線的建構函式:
public DbContext(DbConnection existingConnection, bool contextOwnsConnection)
public DbContext(DbConnection existingConnection, DbCompiledModel model, bool contextOwnsConnection)
您可以使用這些限制,但您必須解決幾項限制:
- 如果您將開啟的連接傳遞給其中一個,則第一次嘗試使用它架構時,會擲回 InvalidOperationException,表示無法重新開啟已開啟的連接。
- 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
}
}
}