Entity Framework C# 中的 EDMX 使用@p__linq__0 隐藏参数值
Entity Framework EDMX in C# hiding parameter values with @p__linq__0
我继承了一些项目,其中 VS 应用程序显然使用旧的 EDMX。我不记得过去有过如此困难的查询,尤其是在计算参数时..
当我逐步执行代码时,我看到了各种 IQueryable<T>
语句,例如
IQueryable<BreakDomainModel> breakDomainModels = breakFactoryService.ReadBreakData();
大家好像都隐藏的太深了,排查起来很困难。
部分例子SQL
CASE WHEN ([Extent2].[BreakId] IS NOT NULL) THEN [Extent3].[Name] ELSE @p__linq__0 END AS [C6],
CASE WHEN ([Extent2].[BreakId] IS NOT NULL) THEN CAST( [Extent2].[DateCreated] AS datetime2) END AS [C7],
[Extent1].[ExceptionType] AS [ExceptionType],
[Extent1].[LinkId] AS [LinkId],
CASE WHEN ([Extent2].[BreakId] IS NOT NULL) THEN [Extent2].[Age] ELSE @p__linq__1 END AS [C8]
如何单步执行代码并实际获取 @p__linq__0
等的值?
如果需要,我可以提供更多代码,但简单的 F11 和使用手表是无济于事的。
运行 SQL 探查器会话可能最容易查看生成的查询。
请参阅此答案以获得更好的解决方案:
View Generated Sql
您可以注册自己的 DbCommandInterceptor. Take a look at this 关于 EF 日志记录的文章。请注意,为了记录参数,您必须迭代 DbCommand.Parameters
。记录 Select 查询的最小解决方案是:
public class LoggingCommandInterceptor : DbCommandInterceptor
{
public override void ReaderExecuting(DbCommand command,
DbCommandInterceptionContext<DbDataReader> interceptionContext)
{
var parameters = command.Parameters.Cast<DbParameter>()
.Select(x => $"{x.ParameterName}:{x.Value}");
// It's up to you how you initialize the logger
GetLogger().Debug($"Parameters: {string.Join(", ", parameters)}\r\n Query: {command.CommandText}");
base.ReaderExecuting(command, interceptionContext);
}
}
然后您需要做的就是在您的应用程序启动代码中注册该拦截器 (global.asax/Startup.cs/etc):
DbInterception.Add(new LoggingCommandInterceptor());
如果您只关心在调试时获取参数,只需在方法内放置一个断点,每次 EF 访问数据库时都会命中。
请注意,您必须以相同的方式覆盖其他方法(NonQueryExecuting()
和 ScalarExecuting()
),以便也拦截 update/instert/delete 查询。
我继承了一些项目,其中 VS 应用程序显然使用旧的 EDMX。我不记得过去有过如此困难的查询,尤其是在计算参数时..
当我逐步执行代码时,我看到了各种 IQueryable<T>
语句,例如
IQueryable<BreakDomainModel> breakDomainModels = breakFactoryService.ReadBreakData();
大家好像都隐藏的太深了,排查起来很困难。
部分例子SQL
CASE WHEN ([Extent2].[BreakId] IS NOT NULL) THEN [Extent3].[Name] ELSE @p__linq__0 END AS [C6],
CASE WHEN ([Extent2].[BreakId] IS NOT NULL) THEN CAST( [Extent2].[DateCreated] AS datetime2) END AS [C7],
[Extent1].[ExceptionType] AS [ExceptionType],
[Extent1].[LinkId] AS [LinkId],
CASE WHEN ([Extent2].[BreakId] IS NOT NULL) THEN [Extent2].[Age] ELSE @p__linq__1 END AS [C8]
如何单步执行代码并实际获取 @p__linq__0
等的值?
如果需要,我可以提供更多代码,但简单的 F11 和使用手表是无济于事的。
运行 SQL 探查器会话可能最容易查看生成的查询。
请参阅此答案以获得更好的解决方案: View Generated Sql
您可以注册自己的 DbCommandInterceptor. Take a look at this 关于 EF 日志记录的文章。请注意,为了记录参数,您必须迭代 DbCommand.Parameters
。记录 Select 查询的最小解决方案是:
public class LoggingCommandInterceptor : DbCommandInterceptor
{
public override void ReaderExecuting(DbCommand command,
DbCommandInterceptionContext<DbDataReader> interceptionContext)
{
var parameters = command.Parameters.Cast<DbParameter>()
.Select(x => $"{x.ParameterName}:{x.Value}");
// It's up to you how you initialize the logger
GetLogger().Debug($"Parameters: {string.Join(", ", parameters)}\r\n Query: {command.CommandText}");
base.ReaderExecuting(command, interceptionContext);
}
}
然后您需要做的就是在您的应用程序启动代码中注册该拦截器 (global.asax/Startup.cs/etc):
DbInterception.Add(new LoggingCommandInterceptor());
如果您只关心在调试时获取参数,只需在方法内放置一个断点,每次 EF 访问数据库时都会命中。
请注意,您必须以相同的方式覆盖其他方法(NonQueryExecuting()
和 ScalarExecuting()
),以便也拦截 update/instert/delete 查询。