簡體   English   中英

DbContext 的自定義連接打開/關閉

[英]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超出范圍,它不會被關閉。 因此,您必須通過調用CloseDispose顯式關閉連接。 CloseDispose在功能上是等效的。 如果連接池值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.  
    } 

您可以閱讀更多的細節文章。 EF.Core 和連接池這個

相關的問題。 實體框架和連接池

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM