簡體   English   中英

通過 IDbCommandInterceptor 檢測或傳遞 Entity Framework 6 和 Entity Framework Core 中的調用方法

[英]Detect or pass calling method in Entity Framework 6 and Entity Framework Core via IDbCommandInterceptor

我有興趣捕獲啟動實體框架查詢的方法的名稱。 我將在 Entity Framework 6 和 Entity Framework Core 中使用此功能

考慮以下 class:

namespace MyCompany.MyApp
{
    public class MyDataClass
    {
        // ... snip ...
        
        public Person GetPerson(long id)
        {
            return _dbContext
                .Person
                .FirstOrDefault(p => p.Id == id);
        }
    }
}

以及以下攔截器:

public class EFCommandInterceptor : IDbCommandInterceptor
{
    // ... snip other interface methods ...

    public void ReaderExecuted(System.Data.Common.DbCommand command, DbCommandInterceptionContext<System.Data.Common.DbDataReader> interceptionContext)
    {
        var callingMehtod = GetCallingMethod() // <--- I'd like this to return the string "MyCompany.MyApp.MyDataClass.GetPerson"
    }
}

有什么方法可以確定是什么方法啟動了導致調用攔截器的查詢?

由於我將使用此功能進行跟蹤和性能分析,因此我無法為通過系統運行的每個查詢發送和記錄整個Environment.StackTrace

我還考慮將StackTrace class 與stackTrace.GetFrames()結合使用來嘗試分析調用堆棧以找到啟動查詢的實際方法,但目前尚不清楚如何在不依賴於某種命名空間約定的情況下可靠地執行此操作通用標識數據訪問 class。

另一種可以接受的方法可能類似於:

namespace MyCompany.MyApp
{
    public class MyDataClass
    {
        // ... snip ...
        
        public Person GetPerson(long id)
        {
            return _dbContext
                .Person
                .WithExtraInterceptorContext(new { CallingMethod = "MyCompany.MyApp.MyDataClass.GetPerson"}) // <--- Can something like this be done?
                .FirstOrDefault(p => p.Id == id);
        }
    }
}

上面示例的意圖是稍后能夠通過IDbCommandInterceptor中的DbCommandInterceptionContext檢索額外的上下文

最終,我要解決的問題是在沒有完整調用堆棧的情況下獲取啟動查詢的方法的完全限定名稱。

使用 EF Core,您可以使用 TagWith

var result = db.Albums
               .TagWith(MethodBase.GetCurrentMethod().Name)
               .ToList();

您可以在運行查詢之前簡單地注冊信息,例如:

    public Person GetPerson(long id)
    {
        EfDebug.SetCurrentMethodName();
        return _dbContext
            .Person
            .WithExtraInterceptorContext(new { CallingMethod = "MyCompany.MyApp.MyDataClass.GetPerson"}) // <--- Can something like this be done?
            .FirstOrDefault(p => p.Id == id);
    }

. . .

   static class EfDebugExtensions
    {
        public static AsyncLocal<string> CurrentMethodName = new AsyncLocal<string>();
        public static void SetCurrentMethodName([CallerMemberName] string caller = "")
        {
            CurrentMethodName.Value = caller;
        }
        public static TSource FirstOrDefault<TSource>(this IEnumerable<TSource> source,[CallerMemberName] string caller = "")
        {
            CurrentMethodName.Value = caller;
            var rv = Enumerable.FirstOrDefault(source);
            return rv;
        }
        public static List<TSource> ToList<TSource>(this IEnumerable<TSource> source, [CallerMemberName] string caller = "")
        {
            CurrentMethodName.Value = caller;
            var rv = Enumerable.ToList(source);
            return rv;
        }

    }

暫無
暫無

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

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