[英]Custom connection opening/closing for DbContext
默認情況下,EF Core 為每個查詢打開和關閉一個DbConnection
,除非您傳入一個已經打開的連接。
我有很多小查詢,所以我不想每次打開和關閉連接,而是希望每次保持連接打開五秒鍾,同時為每個查詢/命令重用該連接。 (上面鏈接的問題的解決方案使連接在 DBContext 的整個生命周期中保持打開狀態。)
撇開鎖定/並發問題不談,我在哪里可以在DbContext
注入自定義連接解析/打開邏輯? 就像是
before executing query:
if connection is not open
open
set timer to fire close request in five seconds
take lock on connection (to prevent closing)
execute query
release lock
這是進行交易的標准方式。 您可以組合多個查詢。
using (var context = new SchoolContext())
{
var std = new Student()
{
FirstName = "Bill",
LastName = "Gates"
};
context.Students.Add(std);
// or
// context.Add<Student>(std);
context.SaveChanges();
std = context.Students.First<Student>();
std.FirstName = "Steve";
context.SaveChanges();
}
ef 核心可以使用相同或不同的連接或基於連接池。 Ef 核心具有連接和斷開的交易模式。 我認為這可以適合你。 在斷開連接的情況下保存數據與在連接的情況下略有不同。 在斷開連接的情況下,DbContext 不知道斷開連接的實體,因為在當前 DbContext 實例的范圍之外添加或修改了實體。 因此,您需要將斷開連接的實體附加到具有適當 EntityState 的上下文,以便對數據庫執行 CUD(創建、更新、刪除)操作。
下圖說明了斷線場景下的CUD操作:
根據上圖,斷開連接的實體(未被 DbContext 跟蹤的實體)需要使用適當的 EntityState 附加到 DbContext。 例如,新實體的添加狀態、已編輯實體的修改狀態和已刪除實體的已刪除狀態,這將在調用 SaveChanges() 方法時在數據庫中產生 INSERT、UPDATE 或 DELETE 命令。
為了在斷開連接的情況下使用 Entity Framework Core 將記錄插入、更新或刪除到數據庫表中,必須執行以下步驟:
使用適當的 EntityState 將實體附加到 DbContext,例如添加、修改或刪除調用 SaveChanges() 方法以下示例演示使用上述步驟將新記錄插入到數據庫中:
//Disconnected entity
var std = new Student(){ Name = "Bill" };
using (var context = new SchoolContext())
{
//1. Attach an entity to context with Added EntityState
context.Add<Student>(std);
//or the followings are also valid
// context.Students.Add(std);
// context.Entry<Student>(std).State = EntityState.Added;
// context.Attach<Student>(std);
//2. Calling SaveChanges to insert a new record into Students table
context.SaveChanges();
}
在上面的示例中,std 是 Student 實體的一個斷開連接的實例。 context.Add() 方法將 Student 實體附加到具有已添加狀態的上下文。 SaveChanges() 方法構建並執行以下 INSERT 語句:
exec sp_executesql N'SET NOCOUNT ON; https://www.entityframeworktutorial.net/efcore/saving-data-in-disconnected-scenario-in-ef-core.aspx這些是重要的方法。
public DbContext(DbConnection existingConnection, bool contextOwnsConnection)
public DbContext(DbConnection existingConnection, DbCompiledModel model, bool contextOwnsConnection)
EF6 和未來版本中的行為對於 EF6 和未來版本,我們采取的方法是,如果調用代碼選擇通過調用 context.Database.Connection.Open() 來打開連接,那么它有這樣做的充分理由,並且框架將假設它想要控制連接的打開和關閉,並且不再自動關閉連接。
筆記
這可能會導致連接長時間打開,因此請謹慎使用。
我們還更新了代碼,以便 ObjectContext.Connection.State 現在可以正確跟蹤底層連接的狀態。
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
}
}
}
https://docs.microsoft.com/en-us/ef/ef6/fundamentals/connection-management?redirectedfrom=MSDN
在 ADO.NET 中,您可以配置連接池以滿足您的要求
為每個唯一的連接字符串創建一個連接池。 創建池時,會創建多個連接對象並將其添加到池中,以滿足最小池大小要求。 連接會根據需要添加到池中,直至指定的最大池大小(默認值為 100)。 連接在關閉或處置時會釋放回池中。
連接池程序通過在連接被釋放回池時重新分配連接來滿足連接請求。 如果已達到最大池大小並且沒有可用的可用連接,則請求將排隊。 然后池程序嘗試回收所有連接,直到達到超時(默認為 15 秒)。 如果池化器在連接超時前無法滿足請求,則拋出異常。
在連接池空閑大約 4-8 分鍾后,或者連接池程序檢測到與服務器的連接已被切斷時,連接池程序會從池中刪除連接。 請注意,只有在嘗試與服務器通信后才能檢測到斷開的連接。 如果發現不再連接到服務器的連接,則將其標記為無效。 無效的連接只有在關閉或回收時才會從連接池中刪除。
如果
SqlConnection
超出范圍,它不會被關閉。 因此,您必須通過調用Close
或Dispose
顯式關閉連接。Close
和Dispose
在功能上是等效的。 如果連接池值Pooling
設置為true
或 yes,則底層連接返回到連接池。 另一方面,如果 Pooling 設置為 false 或 no,則與服務器的底層連接實際上已關閉。
using (SqlConnection connection = new SqlConnection("Integrated Security=SSPI;Initial Catalog=Northwind"))
{
connection.Open();
// Pool A is created.
}
using (SqlConnection connection = new SqlConnection("Integrated Security=SSPI;Initial Catalog=pubs"))
{
connection.Open();
// Pool B is created because the connection strings differ.
}
using (SqlConnection connection = new SqlConnection("Integrated Security=SSPI;Initial Catalog=Northwind"))
{
connection.Open();
// The connection string matches pool A.
}
相關的問題。 實體框架和連接池
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.