簡體   English   中英

.NET 6 使用依賴注入的實體框架跟蹤

[英].NET 6 Entity Framework Tracking with Dependency Injection

我想我只是不了解 EF 跟蹤。 我通過依賴注入添加了上下文:

builder.Services.AddDbContext<OracleContext>(options => options.UseOracle(OracleConnectionString, b => b.UseOracleSQLCompatibility("11"))
                          .LogTo(s => System.Diagnostics.Debug.WriteLine(s))
                          .EnableDetailedErrors(Settings.Dev_System)
                          .EnableSensitiveDataLogging(Settings.Dev_System)
                          .UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking));

我在這里將跟蹤行為設置為 NoTracking(至少我是這么認為的)。

我有一個 .NET Controller,它的構造函數中有上下文。 它將此上下文傳遞給包含我的方法的 class 構造函數。 幾乎一切正常......除了一個:

我有一個執行 context.RawSqlQuery 的方法來獲取對象列表。 我迭代這些對象,從以相同方式(使用注入上下文)生成的不同 class 調用兩個單獨的方法。 此方法首先執行 EF 查詢以驗證 object 是否不存在,如果存在則返回它,我們繼續 - 沒有問題。 在檢查它是否存在的查詢中,我還為 SnG 添加了 AsNoTracking()。 但是,如果 object 不存在,我會嘗試創建一個新的......每次我做一個 context.add 我得到

“無法跟蹤實體類型 'Whatever' 的實例,因為已跟蹤具有鍵值 '{MfrId: 90}' 的另一個實例。附加現有實體時,確保只附加一個具有給定鍵值的實體實例。 “

我嘗試添加 db.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking - 沒有變化我嘗試添加 context.Entry(NewItem).State = EntityState.Detached; 通話前后 - 沒有變化。 我在上下文中嘗試了一個循環,該循環獲取所有被跟蹤的對象並將它們設置為分離 - 沒有變化。

我在這里錯過了什么? 首先 - 它為什么要跟蹤? 第二 - 關於如何通過這個的任何建議? 我是否應該放棄對上下文使用依賴注入(糟透了……為此需要大量返工)?

根據要求 - 這是失敗的 class 和方法(刪除了不相關的內容):

public class AssetMethods : IAssetMethods
    {
        public OracleContext db; 
        

        public AssetMethods(OracleContext context)
        {
            db = context;   
        }
 
        public CcpManufacturer? CreateNewManufacturer(CcpManufacturer NewMan, string ActorID)
        {
            ...blah blah non DB validation stuff removed...

            //Check if it exists already
            CcpManufacturer? OldMan = db.CcpManufacturers.Where(m=>m.MfrName == NewMan.MfrName).AsNoTracking().FirstOrDefault();
            if (OldMan != null) { 
                return OldMan;
            }

            //Who done did it
            NewMan.CreatedBy = ActorID;
            NewMan.CreationDate = DateTime.Now;
            NewMan.Isenabled = true;            

            //save                         
            db.CcpManufacturers.Add(NewMan);           
            db.SaveChanges(); //fails here

            //Prevent XSS Reflection
            return db.CcpManufacturers.Find(NewMan.MfrId);
        }
    }

從此代碼調用此方法。 OM 也在使用注入的上下文

List<MasterItem> Items = OM.RawSqlQuery(Query, x => new MasterItem { MFR_NAME = (string)x[0], MODEL_NUMBER = (string)x[1], LEGAL_NAME= (string)x[2]});

            foreach (MasterItem item in Items)
            {
                CcpManufacturer? Man = new() {
                      MfrName = item.MFR_NAME,
                      Displayname = item.MFR_NAME
                };

                Man = AM.CreateNewManufacturer(Man,System.Id); //if its new.. it never get passed here because of the discussed error...
                if (Man == null || Man.MfrId == 0)
                {
                    continue;
                }
                .... other stuff
             }


因此,mfr id 被添加到一個新的 object 中,該 object 被傳遞給一個幾乎相同的方法來創建一個項目(其中附有 mfr id)。 現在 - 如果我拆下那個項目 - 我沒問題。 但是,當我幾乎在所有地方都將其關閉時,為什么它仍在跟蹤?

是的,你發現了你的問題。

關閉跟蹤會影響 EF 在查詢實體時執行的操作。 這意味着當我告訴 EF 從數據庫中讀取數據並給我實體時,它不會掛在這些實體的引用上。

但是,無論您的跟蹤設置如何,您告訴 DBContext 添加到 DbSet 的實體和相關實體都將被跟蹤。

所以如果我做類似的事情:

var entity1 = context.Entities.Single(x => x.Id == entityId).AsNoTracking();

var entity2 = context.Entities.Single(x => x.Id == entityId).AsNoTracking();

對 entity1 和 entity2 的引用將是對同一記錄的 2 個不同引用。 兩者都是分離的,因此 DbContext 不會跟蹤它們中的任何一個。 我可以使用並附加它們中的任何一個來執行更新,但是從那時起該實體將被視為已附加,直到我再次明確分離它。 嘗試使用其他參考進行更新將導致該錯誤。 如果我在附加並更新第一個實體引用后查詢指定 NoTracking,我將取回一個新的未跟蹤實體引用。 DbContext 不會返回它的跟蹤引用,但它也不會丟棄它。

如果我添加一個新實體然后查詢它並指定 NoTracking,則會發生完全相同的事情。 查詢返回未跟蹤的引用。 因此,如果您嘗試附加它來更新一行,EF 將抱怨它已經在跟蹤的引用。

我不建議深入繞過分離實體的兔子洞,除非你熱衷於花時間真正了解幕后發生的事情,並為非常慎重和謹慎地處理引用做好准備。 其影響不僅僅是事情沒有按預期工作,它是讓事情在完全情境的基礎上工作或不工作,這可能是一件令人討厭的調試和修復事情,即使你知道要尋找什么。

暫無
暫無

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

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