【问题标题】:How to know which Linq statement produced the SQL on hand during runtime?如何知道哪个 Linq 语句在运行时生成了手头的 SQL?
【发布时间】:2015-01-16 17:29:31
【问题描述】:

我想以某种方式编写 Entity Framework 或 LINQ to SQL 查询,以便当我在 SQL Server Profiler 中看到 SQL 查询时,我可以快速确定哪个 LINQ 语句生成了该 SQL,而无需进入调试器并对其进行跟踪.该应用程序不会使用存储过程,因此可以很容易地通过过程名称进行搜索。

有什么想法吗?有没有办法在 LINQ 查询中注入带有代码的静态字符串,仅用于识别查询而不影响查询结果?

更新
我添加这个以响应日志记录建议。我不想让日志一直在生产中运行,以防万一出现问题时我需要查看一些 SQL。寻找一种对性能成本最低的方法。将一些唯一的字符串附加到每个 linq 语句,以便代码可以很容易地与 SQL 相关联?

【问题讨论】:

  • 使用 Linq2SQl,您可以将 Log 属性设置为任何 TextWriter,不确定 EF。
  • @leppie 我不想记录。这可以在生产中
  • 为什么不按进程过滤(假设所有内容都来自“linq”)?
  • 一切都来自 IIS。这是一个 ASP.NET 应用程序。我不明白按进程过滤如何告诉您哪个 SQL 与哪个 LINQ 语句一起使用。

标签: c# linq entity-framework linq-to-sql linq-to-entities


【解决方案1】:

这是一种可用于标记实体框架查询的扩展方法:

public static class ExtensionMethods
{
  public static IQueryable<T> SetQueryName<T>(this IQueryable<T> source,
    [CallerMemberName] String name = null,
    [CallerFilePath] String sourceFilePath = "",
    [CallerLineNumber] Int32 sourceLineNumber = 0)
  {
    var expr = Expression.NotEqual(Expression.Constant("Query name: " + name), Expression.Constant(null));
    var param = Expression.Parameter(typeof(T), "param");
    var criteria1 = Expression.Lambda<Func<T, Boolean>>(expr, param);

    expr = Expression.NotEqual(Expression.Constant($"Source: {sourceFilePath} ({sourceLineNumber})"), Expression.Constant(null));
    var criteria2 = Expression.Lambda<Func<T, Boolean>>(expr, param);

    return source.Where(criteria1).Where(criteria2);
  }
}

这里是如何使用它:

context.Table1.SetQueryName().Where(x => x.C1 > 4)

它将使用调用方法名称作为查询名称。

您可以像这样指定另一个名称:

context.Table1.SetQueryName("Search for numbers > 4").Where(x => x.Number > 4)

下面是 SQL 的样子:

SELECT 
    [Extent1].[Number] AS [Number]
    FROM (SELECT 
    [Table1].[Number] AS [Number]
    FROM [dbo].[Table1] AS [Table1]) AS [Extent1]
    WHERE
      (N'Query name: Search for numbers > 4' IS NOT NULL)
      AND
      (N'Source: C:\Code\Projects\MyApp\Program.cs (49)' IS NOT NULL)
      AND ([Extent1].[Number] > 4)

【讨论】:

  • 太棒了!你是一个 LINQ 向导。我需要的一切都显示在 SQL Profiler 中。谢谢。
【解决方案2】:

您可以使用ToTraceString 方法查看生成的SQL。或者使用 LINQPad 之类的东西来测试查询。

ToTraceString 文档:http://msdn.microsoft.com/en-us/library/system.data.objects.objectquery.totracestring(v=vs.110).aspx

【讨论】:

  • 我不想一直运行日志记录,特别是在生产环境中
【解决方案3】:

这真的很奇怪,而且会有一点性能开销......

但您可能会执行一些操作,例如将不可能的已知标记值与聚集索引进行比较:

var queryId = -123456789;

this.Products
    .Where(p => p.ProductId != -queryId);

生成的 SQL 将包含 Id:

DECLARE @p0 Int = -456789
SELECT ....
FROM [Product] AS [t0]
WHERE [t0].[ProductId] <> @p0

我完全建议在生产中做这样的事情:D

如果您要比较的列没有索引,您最终会遇到可怕的表扫描,这会降低性能。

【讨论】:

    【解决方案4】:

    如果您使用 MiniProfiler,它可以为您提供一个方便的小面板,显示在您的请求中不同位置生成的 SQL。它包括运行查询时堆栈上所有方法的名称。这与提供 LINQ 查询的完整字符串表示并不完全相同,但它实际上可能就是您要查找的内容。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-06
      • 2017-09-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多