3

我们正在使用 newrelic 进行数据库性能监控。我们的问题是实体框架正在生成 SQL,并且我们在跟踪此 SQL 查询在我们的代码库中生成的位置时遇到问题,例如

假设以下查询导致性能问题。例如,如何修改生成的 sql 查询并在其上添加自定义注释

SELECT 
    ? AS [C1], 
    [GroupBy1].[K1] AS [Destination], 
    [GroupBy1].[A1] AS [C2]
    FROM ( SELECT 
        [Extent1].[Destination] AS [K1], 
        SUM([Extent1].[SearchCount]) AS [A1]
        FROM [Flight].[Item] AS [Extent1]
        WHERE ([Extent1].[Origin] IN (?, ?)) AND ( NOT ((@p__linq__0 = ?) AND ([Extent1].[IsDomesticTurkish] = ?))) AND ([Extent1].[DestinationCity] IN (?, ?, ?, ?, ?, ?, ?, ?)) AND ([Extent1].[DestinationCity] IS NOT NULL)
        GROUP BY [Extent1...More…

那么我该如何做这样的事情 var DbContext.MyDbSet.Where(myWhereEx).AddCustomComment("Hello this is a custom comment I will write it from my code")

之后的输出将是这样的

SELECT 
    ? AS [C1], 
    [GroupBy1].[K1] AS [Destination], 
    [GroupBy1].[A1] AS [C2]
    FROM ( SELECT 
        [Extent1].[Destination] AS [K1], 
        SUM([Extent1].[SearchCount]) AS [A1]
        FROM [Flight].[Item] AS [Extent1]
        WHERE ([Extent1].[Origin] IN (?, ?)) AND ( NOT ((@p__linq__0 = ?) AND ([Extent1].[IsDomesticTurkish] = ?))) AND ([Extent1].[DestinationCity] IN (?, ?, ?, ?, ?, ?, ?, ?)) AND ([Extent1].[DestinationCity] IS NOT NULL)
        GROUP BY [Extent1...More…

--Hello this is a custom comment I will write it from my code

我的问题是如何实现 AddCustomComment 并在 AddCustomComment 内部修改生成的 sql 在它进入 SQL 服务器之前

4

1 回答 1

1

我不知道有任何 EF 内置功能可以做到这一点,但这里有一个想法是如何做到这一点的。

您可以使用线程局部变量来存储注释(因此每个线程都有自己的该变量的副本)并使用实体框架命令拦截器在执行命令之前向命令添加注释,然后在执行命令时清除注释变量。这是示例实现:

class EFCommentInterceptor : IDbCommandInterceptor {
    private static readonly ThreadLocal<string> _comment = new ThreadLocal<string>();

    internal static void SetComment(string comment) {
        _comment.Value = comment;
    }

    public void NonQueryExecuting(DbCommand command, DbCommandInterceptionContext<int> interceptionContext) {
        AddComment(command);
    }

    public void NonQueryExecuted(DbCommand command, DbCommandInterceptionContext<int> interceptionContext) {
        _comment.Value = null;
    }

    public void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext) {
        AddComment(command);
    }

    public void ReaderExecuted(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext) {
        _comment.Value = null;
    }

    public void ScalarExecuting(DbCommand command, DbCommandInterceptionContext<object> interceptionContext) {
        AddComment(command);
    }

    public void ScalarExecuted(DbCommand command, DbCommandInterceptionContext<object> interceptionContext) {
        _comment.Value = null;
    }

    private void AddComment(DbCommand command) {
        if (!String.IsNullOrWhiteSpace(_comment.Value))
            command.CommandText += "\r\n\r\n-- " + _comment.Value;
    }
}

然后像这样添加扩展方法:

static class QueryableExtensions {
    public static IQueryable<T> WithComment<T>(this IQueryable<T> query, string comment) {
        EFCommentInterceptor.SetComment(comment);
        return query;
    }
}

注册拦截器:

DbInterception.Add(new EFCommentInterceptor());

并使用它:

using (var ctx = new MyContext()) {
    ctx.MyDbSet.Where(c = c.MyColumn > 1).WithComment("Hello this is a custom comment I will write it from my code").ToArray();
    ctx.MyDbSet.Take(10).ToArray(); // no comment here
    ctx.MyDbSet.Take(10).WithComment("Again with comment").ToArray();
}
于 2017-02-13T14:56:33.853 回答