记录EFCore产生的SQL语句到日志

本文介绍如何在EFCore中自定义记录SQL语句到日志的方法,包括创建自定义LoggerProvider和ILogger,并通过DbContextOptionsBuilder配置日志记录。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

记录EFCore产生的SQL语句到日志

以下以ABP项目为例子

1, 先创建LoggerProvider

using Microsoft.Extensions.Logging;
using System;

namespace demo
{
    public class EfLoggerProvider : ILoggerProvider
    {
        public Castle.Core.Logging.ILogger Logger;

        public EfLoggerProvider(Castle.Core.Logging.ILogger logger)
        {
            Logger = logger;
        }

        public ILogger CreateLogger(string categoryName)
        {
            return new EfLogger(categoryName, Logger);
        }

        public void Dispose()
        {
        }
    }

    public class EfLogger : ILogger
    {
        public Castle.Core.Logging.ILogger Logger { get; set; }

        private readonly string _categoryName;

        public EfLogger(string categoryName, Castle.Core.Logging.ILogger logger)
        {
            this._categoryName = categoryName;
            this.Logger = logger;
        }

        public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
        {
            //ef core执行数据库查询时的categoryName为Microsoft.EntityFrameworkCore.Database.Command,日志级别为Information
            //过滤掉了定时任务的日志,读取多语言,记录接口日志等SQL
            var logContent = formatter(state, exception);

            if (logLevel == LogLevel.Error)
            {
                Logger.Fatal(logContent); //错误日志
                return;
            }

            //过滤掉定时任务等脚本的日志
            if (logContent.Contains("AbpBackgroundJob") || logContent.Contains("AbpLanguage") || logContent.Contains("AbpAuditLog") || logContent.Contains("AbpSetting"))
            {
                return;
            }

            if (_categoryName == "Microsoft.EntityFrameworkCore.Database.Command" && logLevel == LogLevel.Debug && logContent.Contains("Executing DbCommand"))
            {
                Logger.Fatal(logContent); //创建的sql
                return;
            }
        }

        IDisposable ILogger.BeginScope<TState>(TState state)
        {
            return null;
        }

        public bool IsEnabled(LogLevel logLevel) => true;
    }
}

2, 创建LoggerFactory,并给DbContextOptionsBuilder使用

public class bsmEntityFrameworkModule : AbpModule
{
	/* Used it tests to skip dbcontext registration, in order to use in-memory database of EF Core */

	public override void PreInitialize()
	{
		if (!SkipDbContextRegistration)
		{
			Configuration.Modules.AbpEfCore().AddDbContext<bsmDbContext>(options =>
			{
				if (options.ExistingConnection != null)
				{
					bsmDbContextConfigurer.Configure(options.DbContextOptions, options.ExistingConnection);
				}
				else
				{
					//2,在这里使用
					bsmDbContextConfigurer.Configure(options.DbContextOptions, options.ConnectionString, DbLoggerFactory);
				}
			});
		}
	}

 ......

	//1,构建单例对象,记录数据库日志
	private static LoggerFactory _loggerFactory { get; set; }

	private Microsoft.Extensions.Logging.LoggerFactory DbLoggerFactory
	{
		get
		{
			if (null == _loggerFactory)
			{
				_loggerFactory = new Microsoft.Extensions.Logging.LoggerFactory();
				_loggerFactory.AddProvider(new EfLoggerProvider(Logger));
			}

			return _loggerFactory;
		}
	}
}

配合修改DbContextConfigurer

using System.Data.Common;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;

namespace Best.EntityFrameworkCore
{
    public static class BestDbContextConfigurer
    {
        public static void Configure(DbContextOptionsBuilder<BestDbContext> builder, string connectionString, ILoggerFactory _loggerFactory)
        {
            //使用传进来的_loggerFactory
            builder.UseLoggerFactory(_loggerFactory).UseSqlServer(connectionString);
            builder.EnableSensitiveDataLogging(); //日志显示脚本参数
        }

        public static void Configure(DbContextOptionsBuilder<BestDbContext> builder, DbConnection connection)
        {
            builder.UseSqlServer(connection);
        }
    }
}

log4net.config推荐配置

<?xml version="1.0" encoding="utf-8"?>

<log4net>
	<!-- 全部的日志 OFF > FATAL > ERROR > WARN > INFO > DEBUG  > ALL  -->
	<!-- 正在执行的sql -->
	<appender name="SQLExecuting" type="log4net.Appender.RollingFileAppender" >
		<file value="App_Data/Logs/SQLExecuting" />
		<appendToFile value="true" />
		<rollingStyle value="Date" />
		<datePattern value="yyyyMM\\'SQL'yyyyMMddHH'.txt'"/>
		<maxSizeRollBackups value="100" />
		<maximumFileSize value="10MB" />
		<staticLogFileName value="false" />
		<layout type="log4net.Layout.PatternLayout">
			<conversionPattern value="%newline%date [%thread] [%-5level] %logger %newline%message%newline"/>
		</layout>
		<filter type="log4net.Filter.LevelRangeFilter">
			<levelMin value="Fatal" />
			<acceptOnMatch value="false" />
		</filter>
		<filter type="log4net.Filter.StringMatchFilter">
			<stringToMatch value="Executed" />
			<!-- 不显示包含executed的日志 -->
			<acceptOnMatch value="false" />
		</filter>
	</appender>

	<appender name="Error" type="log4net.Appender.RollingFileAppender" >
		<file value="App_Data/Logs/Error" />
		<appendToFile value="true" />
		<rollingStyle value="Date" />
		<datePattern value="yyyyMM/'Error'yyyyMMddHH'.txt'"/>
		<maxSizeRollBackups value="100" />
		<maximumFileSize value="10MB" />
		<staticLogFileName value="false" />
		<layout type="log4net.Layout.PatternLayout">
			<conversionPattern value="%newline%date [%thread] [%-5level] %logger property: [%property{NDC}] %newline%message%newline"/>
		</layout>
		<filter type="log4net.Filter.LevelRangeFilter">
			<levelMin value="Error" />
		</filter>
	</appender>

	<appender name="Info" type="log4net.Appender.RollingFileAppender" >
		<file value="App_Data/Logs/Info" />
		<appendToFile value="true" />
		<rollingStyle value="Composite" />
		<datePattern value="yyyyMM\\'Info'yyyyMMddHH'.txt'"/>
		<maxSizeRollBackups value="100" />
		<maximumFileSize value="10MB" />
		<staticLogFileName value="false" />
		<layout type="log4net.Layout.PatternLayout">
			<conversionPattern value="%newline%date [%thread] [%-5level] %logger %newline%message%newline"/>
		</layout>
		<filter type="log4net.Filter.LevelRangeFilter">
			<levelMin value="Info" />
			<levelMax value="Info" />
		</filter>
	</appender>

	<appender name="Warn" type="log4net.Appender.RollingFileAppender" >
		<file value="App_Data/Logs/Warn" />
		<appendToFile value="true" />
		<rollingStyle value="Composite" />
		<datePattern value="yyyyMM\\'Warn'yyyyMMddHH'.txt'"/>
		<maxSizeRollBackups value="100" />
		<maximumFileSize value="10MB" />
		<staticLogFileName value="false" />
		<layout type="log4net.Layout.PatternLayout">
			<conversionPattern value="%newline%date [%thread] [%-5level] %logger %newline%message%newline"/>
		</layout>
		<filter type="log4net.Filter.LevelRangeFilter">
			<levelMin value="Warn" />
			<levelMax value="Warn" />
		</filter>
	</appender>

	<appender name="Debug" type="log4net.Appender.RollingFileAppender" >
		<file value="App_Data/Logs/Debug" />
		<appendToFile value="true" />
		<rollingStyle value="Composite" />
		<datePattern value="yyyyMM\\'Debug'yyyyMMddHH'.txt'"/>
		<maxSizeRollBackups value="100" />
		<maximumFileSize value="10MB" />
		<staticLogFileName value="false" />
		<layout type="log4net.Layout.PatternLayout">
			<conversionPattern value="%newline%date [%thread] [%-5level] %logger %newline%message%newline"/>
		</layout>
		<filter type="log4net.Filter.LevelRangeFilter">
			<levelMin value="Debug" />
			<levelMax value="Debug" />
		</filter>
	</appender>

	<root>
		<appender-ref ref="Info" />
		<appender-ref ref="Error" />
		<appender-ref ref="Debug" />
		<appender-ref ref="Warn" />
		<appender-ref ref="SQLExecuting" />
		<appender-ref ref="SQLExecuted" />
		<level value="DEBUG" />
		<!-- Debug以上才记录 -->
	</root>

</log4net>
<think>好的,我现在需要帮助用户在Visual Studio 2022中配置EF Core,使其生成的SQL语句输出到控制台。根据用户提供的引用内容,我需要整理出具体的步骤。首先,用户提到了多个方法,比如使用DbContextOptionsBuilder配置日志,或者在OnConfiguring方法中设置LogTo,以及使用LoggerFactory。 首先,我应该确认不同版本的EF Core是否有不同的方法。引用3提到EF Core 2.2使用LogTo(Console.WriteLine),而引用4则提到使用LoggerFactory。可能需要区分版本,但用户没有明确EF Core的版本,所以最好涵盖多种方法。 然后,我需要考虑如何在VS2022中实现这些配置。通常,在DbContext的子类中重写OnConfiguring方法是常见做法。此外,添加控制台日志记录可能需要引入Microsoft.Extensions.Logging.Console包,这点在引用4中提到过,但用户的问题中是否包括安装NuGet包呢?可能需要提醒用户安装必要的包。 接下来,步骤需要分点说明,清晰明了。比如第一步是重写OnConfiguring方法,使用optionsBuilder.LogTo。第二步可能是配置LoggerFactory,并添加到DbContext中。同时,用户可能需要确保引入了正确的命名空间,比如Microsoft.Extensions.Logging。 还需要注意,在.NET Core 3.0及以上版本,LogTo方法是可用的,而旧版本可能需要使用UseLoggerFactory。因此,可能需要根据不同的EF Core版本给出不同的方法。但用户的问题中没有指定版本,可能需要同时提供两种方法,或者推荐较新的方式。 另外,引用1和2中的示例代码使用了UseMySql,但用户的问题是关于输出SQL到控制台,所以重点在日志配置部分,而不是数据库提供程序。需要确保用户明白这些配置是独立于数据库类型的。 可能还需要提醒用户,在开发环境中启用日志记录,但在生产环境中应关闭,以避免性能问题和安全风险。此外,日志级别可能需要设置为Information或更低,以捕获生成的SQL语句。 最后,验证步骤是否有效,比如运行程序并观察控制台输出是否有SQL语句。如果有问题,可能需要检查NuGet包是否正确安装,或者日志级别设置是否正确。 总结一下,我需要将步骤分为几种方法,可能包括使用LogTo方法、配置LoggerFactory,并提及注意事项,如版本差异和必要的包引用。确保用户能够按照步骤操作,并成功看到生成的SQL。</think>在Visual Studio 2022中将EF Core生成的SQL语句输出到控制台,可通过以下两种方法实现: --- ### 方法1:使用`LogTo`方法(推荐,EF Core 5.0+) 1. **重写DbContext的`OnConfiguring`方法** 在自定义的`DbContext`子类中添加以下代码: ```csharp protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.LogTo(Console.WriteLine, LogLevel.Information); // 输出到控制台 // 或输出到调试窗口:LogTo(message => Debug.WriteLine(message)) } ``` 2. **设置日志级别** - `LogLevel.Information`会显示生成的SQL语句 - `LogLevel.Debug`包含更详细的跟踪信息 --- ### 方法2:通过`LoggerFactory`(兼容旧版EF Core) 1. **安装NuGet包** ```bash Install-Package Microsoft.Extensions.Logging.Console ``` 2. **配置DbContext** ```csharp public class MyDbContext : DbContext { private static readonly ILoggerFactory LoggerFactory = Microsoft.Extensions.Logging.LoggerFactory.Create(builder => { builder.AddConsole(); }); protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseLoggerFactory(LoggerFactory); } } ``` --- ### 验证输出效果 运行查询后,控制台会显示类似内容: ```sql Executed DbCommand (12ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] SELECT `u`.`Id`, `u`.`Name` FROM `Users` AS `u` ``` --- ### 注意事项 1. **环境区分** 建议仅在开发环境启用SQL日志,生产环境需关闭[^3] 2. **扩展信息** 若需查看参数值,可在`LogTo`中设置`EnableSensitiveDataLogging=true`[^4] 3. **版本兼容性** - `LogTo`方法适用于EF Core 5.0及以上版本 - `LoggerFactory`适用于EF Core 2.1+
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值