如何知道哪些Linq语句在运行时生成了SQL?

时间:2015-01-16 17:29:31

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

我想以某种方式编写实体框架或LINQ to SQL查询,这样当我在SQL Server Profiler中看到SQL查询时,我可以快速识别哪个LINQ语句产生了SQL,而无需进入调试器并跟踪它。该应用程序不会使用存储过程,这样便于按proc名称进行搜索。

有什么想法吗?有没有办法在LINQ查询中为代码注入静态字符串,只是为了识别查询而不影响查询结果?

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

4 个答案:

答案 0 :(得分:3)

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

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)

答案 1 :(得分:0)

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

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

答案 2 :(得分:0)

这真的很奇怪,性能成本会很低......

但你可能会做一些比较一个已知的不可能的聚集索引的哨兵值:

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

如果您要比较的列没有索引,那么您最终会进行可怕的表扫描,这会导致性能下降。

答案 3 :(得分:0)

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

MiniProfiler screenshot