咱们常常须要在EF Core中记录SQL并更改跟踪信息以进行调试。
EF Core日志记录自动与.NET Core的日志记录机制集成。所以,在隐含使用EF Core的日志记录以前,了解有关.NET Core日志记录的基础知识。
Entity Framework Core与.NET Core日志记录集成在一块儿,以记录SQL并将跟踪信息更改成各类输出目标。首先,安装您选择的日志记录提供程序的Nuget程序包,而后将DbContext绑定到ILoggerFactory。
让咱们安装日志记录提供程序的NuGet软件包。在这里,咱们将在控制台上显示日志,所以从NuGet程序包管理器安装Microsoft.Extensions.Logging.Console NuGet程序包,或在程序包管理器控制台中执行如下命令:web
Install-Package Microsoft.Extensions.Logging.Console
下图说明了DbContext如何与日志记录API和控制台日志记录提供程序一块儿使用。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-afUjJAU3-1581165281344)(d:\note\efcore\pic\27.png)]sql
在安装控制台记录器提供程序以后,您须要建立LoggerFactory的静态/单个实例,而后将其与DbContext绑定,以下所示。数据库
public class SchoolContext : DbContext { //static LoggerFactory object public static readonly ILoggerFactory loggerFactory = new LoggerFactory(new[] { new ConsoleLoggerProvider((_, __) => true, true) }); //or // public static readonly ILoggerFactory loggerFactory = new LoggerFactory().AddConsole((_,___) => true); public SchoolContext():base() { } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseLoggerFactory(loggerFactory) //tie-up DbContext with LoggerFactory object .EnableSensitiveDataLogging() .UseSqlServer(@"Server=.\SQLEXPRESS;Database=SchoolDB;Trusted_Connection=True;"); } public DbSet<Student> Students { get; set; } }
在上面的示例中,咱们建立了LoggerFactory类的对象,并将其分配给ILoggerFactory类型的静态变量。而后,咱们在OnConfiguring()方法的optionsBuilder.UseLoggerFactory()方法中传递了此对象。这将使DbContext与loggerFactory对象共享信息,该对象又将在控制台上显示全部日志记录信息。
默认状况下,EF Core将不记录敏感数据,例如过滤器参数值。所以,调用EnableSensitiveDataLogging()记录敏感数据。
注意:
EF团队建议在应用程序生存期内,将同一个logger工厂对象与DbContext类的全部实例一块儿使用。不然,可能会致使内存泄漏和性能降低。您还能够建立一个单独的工厂类,为您提供LoggerFactory类的单例对象,以与DbContext一块儿使用。
让咱们详细了解上面的示例。
首先,咱们建立了LoggerFactory类的对象,并将其分配给ILoggerFactory类型的静态变量,以下所示。c#
public static readonly ILoggerFactory loggerFactory = new LoggerFactory( new[] { new ConsoleLoggerProvider ((_, __) => true, true) } );
LoggerFactory能够包含一个或多个日志记录提供程序,可用于同时记录到多个介质。 LoggerFactory的构造函数接受一系列不一样的记录器提供程序对象做为new [] {}。咱们但愿在控制台上显示日志,所以建立控制台记录器提供程序ConsoleLoggerProvider的对象。
ConsoleLoggerProvider有四个构造函数。使用容许lambda表达式(Func <>)进行日志过滤的方法,并使用includeScope布尔值,以下所示。bash
new ConsoleLoggerProvider((_, __) => true, true)
在这里,咱们不想过滤任何信息,所以lambda表达式将始终返回true (_, __) => true.app
建立ILoggerFactory对象以后,使用DbContextOptionsBuilder在OnConfiguring()方法中将DbContext与ILoggerFactory绑定在一块儿。ide
optionsBuilder.UseLoggerFactory(loggerFactory)
所以,咱们将DbContext与包括控制台记录器提供程序的LoggerFactory绑定在一块儿。如今,每当DbContext实例执行任何操做时,咱们均可以在控制台上看到全部日志。
考虑如下示例。svg
using (var context = new SchoolContext()) { var std = new Student(){ StudentName = "Steve" }; context.Add(std); context.SaveChanges(); Console.ReadLine(); }
上面的示例将在控制台上显示如下日志:函数
dbug: Microsoft.EntityFrameworkCore.Infrastructure[100401] An 'IServiceProvider' was created for internal use by Entity Framework. info: Microsoft.EntityFrameworkCore.Infrastructure[100403] Entity Framework Core 2.0.0-rtm-26452 initialized 'SchoolContext' using pr ovider 'Microsoft.EntityFrameworkCore.SqlServer' with options: SensitiveDataLoggingEnabled dbug: Microsoft.EntityFrameworkCore.Database.Connection[200000] Opening connection to database 'SchoolDB' on server '.\SQLEXPRESS'. dbug: Microsoft.EntityFrameworkCore.Database.Connection[200001] Opened connection to database 'SchoolDB' on server '.\SQLEXPRESS'. dbug: Microsoft.EntityFrameworkCore.Database.Transaction[200200] Beginning transaction with isolation level 'ReadCommitted'. warn: Microsoft.EntityFrameworkCore.Database.Command[100400] Sensitive data logging is enabled. Log entries and exception messages may include sensitive application data, this mode should only be enabled during development. dbug: Microsoft.EntityFrameworkCore.Database.Command[200100] Executing DbCommand [Parameters=[@p0='' (DbType = DateTime2), @p1='' (DbTy pe = Int32), @p2='0', @p3='' (Size = 8000) (DbType = Binary), @p4='Steve' (Size = 4000), @p5='0'], CommandType='Text', CommandTimeout='30'] SET NOCOUNT ON; INSERT INTO [Students] ([DateOfBirth], [GradeId], [Height], [Photo], [Stud entName], [Weight]) VALUES (@p0, @p1, @p2, @p3, @p4, @p5); SELECT [StudentID] FROM [Students] WHERE @@ROWCOUNT = 1 AND [StudentID] = scope_identity(); info: Microsoft.EntityFrameworkCore.Database.Command[200101] Executed DbCommand (68ms) [Parameters=[@p0='' (DbType = DateTime2), @p1='' (DbType = Int32), @p2='0', @p3='' (Size = 8000) (DbType = Binary), @p4='Steve' (Size = 4000), @p5='0'], CommandType='Text', CommandTimeout='30'] SET NOCOUNT ON; INSERT INTO [Students] ([DateOfBirth], [GradeId], [Height], [Photo], [Stud entName], [Weight]) VALUES (@p0, @p1, @p2, @p3, @p4, @p5); SELECT [StudentID] FROM [Students] WHERE @@ROWCOUNT = 1 AND [StudentID] = scope_identity(); dbug: Microsoft.EntityFrameworkCore.Database.Command[200300] A data reader was disposed. dbug: Microsoft.EntityFrameworkCore.Database.Transaction[200202] Committing transaction. dbug: Microsoft.EntityFrameworkCore.Database.Connection[200002] Closing connection to database 'SchoolDB' on server '.\SQLEXPRESS'. dbug: Microsoft.EntityFrameworkCore.Database.Connection[200003] Closed connection to database 'SchoolDB' on server '.\SQLEXPRESS'. dbug: Microsoft.EntityFrameworkCore.Database.Transaction[200204] Disposing transaction.
如您所见,它记录了全部信息。性能
在上面的示例中,DbContext在保存实体时记录了全部信息。有时您不想记录全部信息并过滤一些不须要的日志。在EF Core中,您能够经过指定记录器类别和日志级别来过滤日志。
EF Core 2.x包含DbLoggerCategory类,以使用其Name属性获取Entity Framework Core记录器类别。下表列出了不一样的记录器类别。
日志类别类 | 描述 |
---|---|
Database.Command | 命令执行的记录器类别,包括发送到数据库的SQL。 |
Database.Connection | 数据库链接操做的记录器类别。 |
Database.Transaction | 数据库事务的记录器类别。 |
Infrastructure | EF基础结构的其余消息的记录器类别。 |
Migration | 迁移的记录器类别。 |
Model | 用于模型构建和元数据的记录器类别。 |
Query | 查询的记录器类别(不包括生成的SQL)。 |
Scaffolding | 脚手架和逆向工程的记录仪类别。 |
Update | DbContext.SaveChanges()消息的记录器类别。 |
要仅记录SQL查询,请在ConsoleLoggerProvider的构造函数的lambda表达式中指定DbLoggerCategory.Database.Command类别和LogLevel.Information,以下所示。
public static readonly ILoggerFactory consoleLoggerFactory = new LoggerFactory(new[] { new ConsoleLoggerProvider((category, level) => category == DbLoggerCategory.Database.Command.Name && level == LogLevel.Information, true) });
或者,默认状况下,只需在LoggerFactory上调用AddConsole()方法便可记录SQL查询。
public static readonly ILoggerFactory consoleLoggerFactory = new LoggerFactory().AddConsole();
如今,这将记录如下查询信息,这些查询信息使用DbContext保存一个实体。
info: Microsoft.EntityFrameworkCore.Database.Command[200101] Executed DbCommand (73ms) [Parameters=[@p0='' (DbType = DateTime2), @p1='' (DbType = Int32), @p2='0', @p3='' (Size = 8000) (DbType = Binary), @p4='Steve' (Size = 4000), @p5='0'], CommandType='Text', CommandTimeout='30'] SET NOCOUNT ON; INSERT INTO [Students] ([DateOfBirth], [GradeId], [Height], [Photo], [Stud entName], [Weight]) VALUES (@p0, @p1, @p2, @p3, @p4, @p5); SELECT [StudentID] FROM [Students] WHERE @@ROWCOUNT = 1 AND [StudentID] = scope_identity();