query net framework debug asp entity-framework ado.net

net - ¿Cómo veo el SQL generado por Entity Framework?



view sql query entity framework (17)

A partir de EF6.1 puede utilizar Interceptores para registrar un registrador de base de datos. Vea los capítulos "Interceptores" y "Operaciones de base de datos de registro" en un archivo here

<interceptors> <interceptor type="System.Data.Entity.Infrastructure.Interception.DatabaseLogger, EntityFramework"> <parameters> <parameter value="C:/Temp/LogOutput.txt"/> <parameter value="true" type="System.Boolean"/> </parameters> </interceptor> </interceptors>

¿Cómo veo el SQL generado por el marco de la entidad?

(En mi caso particular, estoy usando el proveedor mysql, si es importante)


Acabo de hacer esto:

IQueryable<Product> query = EntitySet.Where(p => p.Id == id); Debug.WriteLine(query);

Y el resultado mostrado en la Salida :

SELECT [Extent1].[Id] AS [Id], [Extent1].[Code] AS [Code], [Extent1].[Name] AS [Name], [Extent2].[Id] AS [Id1], [Extent2].[FileName] AS [FileName], FROM [dbo].[Products] AS [Extent1] INNER JOIN [dbo].[PersistedFiles] AS [Extent2] ON [Extent1].[PersistedFileId] = [Extent2].[Id] WHERE [Extent1].[Id] = @p__linq__0


Aplicable para EF 6.0 y superior: para aquellos que quieran saber más sobre la funcionalidad de registro y para agregar algunas de las respuestas ya dadas.

Cualquier comando enviado desde el EF a la base de datos ahora puede ser registrado. Para ver las consultas generadas desde EF 6.x, use la DBContext.Database.Log property

Lo que se registra

- SQL for all different kinds of commands. For example: - Queries, including normal LINQ queries, eSQL queries, and raw queries from methods such as SqlQuery. - Inserts, updates, and deletes generated as part of SaveChanges - Relationship loading queries such as those generated by lazy loading - Parameters - Whether or not the command is being executed asynchronously - A timestamp indicating when the command started executing - Whether or not the command completed successfully, failed by throwing an exception, or, for async, was canceled - Some indication of the result value - The approximate amount of time it took to execute the command. Note that this is the time from sending the command to getting the result object back. It does not include time to read the results.

Ejemplo:

using (var context = new BlogContext()) { context.Database.Log = Console.Write; var blog = context.Blogs.First(b => b.Title == "One Unicorn"); blog.Posts.First().Title = "Green Eggs and Ham"; blog.Posts.Add(new Post { Title = "I do not like them!" }); context.SaveChangesAsync().Wait(); }

Salida:

SELECT TOP (1) [Extent1].[Id] AS [Id], [Extent1].[Title] AS [Title] FROM [dbo].[Blogs] AS [Extent1] WHERE (N''One Unicorn'' = [Extent1].[Title]) AND ([Extent1].[Title] IS NOT NULL) -- Executing at 10/8/2013 10:55:41 AM -07:00 -- Completed in 4 ms with result: SqlDataReader SELECT [Extent1].[Id] AS [Id], [Extent1].[Title] AS [Title], [Extent1].[BlogId] AS [BlogId] FROM [dbo].[Posts] AS [Extent1] WHERE [Extent1].[BlogId] = @EntityKeyValue1 -- EntityKeyValue1: ''1'' (Type = Int32) -- Executing at 10/8/2013 10:55:41 AM -07:00 -- Completed in 2 ms with result: SqlDataReader UPDATE [dbo].[Posts] SET [Title] = @0 WHERE ([Id] = @1) -- @0: ''Green Eggs and Ham'' (Type = String, Size = -1) -- @1: ''1'' (Type = Int32) -- Executing asynchronously at 10/8/2013 10:55:41 AM -07:00 -- Completed in 12 ms with result: 1 INSERT [dbo].[Posts]([Title], [BlogId]) VALUES (@0, @1) SELECT [Id] FROM [dbo].[Posts] WHERE @@ROWCOUNT > 0 AND [Id] = scope_identity() -- @0: ''I do not like them!'' (Type = String, Size = -1) -- @1: ''1'' (Type = Int32) -- Executing asynchronously at 10/8/2013 10:55:41 AM -07:00 -- Completed in 2 ms with result: SqlDataReader

Para iniciar sesión en un archivo externo:

using (var context = new BlogContext()) { using (var sqlLogFile = new StreamWriter("C://temp//LogFile.txt")) { context.Database.Log = sqlLogFile.Write; var blog = context.Blogs.First(b => b.Title == "One Unicorn"); blog.Posts.First().Title = "Green Eggs and Ham"; context.SaveChanges(); } }

Más información aquí: Registrando e interceptando operaciones de base de datos


Bueno, estoy usando Express Profiler para ese propósito en este momento, el inconveniente es que solo funciona para MS SQL Server. Puede encontrar esta herramienta aquí: https://expressprofiler.codeplex.com/


En mi caso para EF 6+, en lugar de usar esto en la ventana Inmediata para encontrar la cadena de consulta:

var sql = ((System.Data.Entity.Core.Objects.ObjectQuery)query).ToTraceString();

Terminé teniendo que usar esto para obtener el comando SQL generado:

var sql = ((System.Data.Entity.Infrastructure.DbQuery<<>f__AnonymousType3<string,string,string,short,string>>)query).ToString();

Por supuesto, su firma de tipo anónimo puede ser diferente.

HTH.


Estoy haciendo una prueba de integración, y necesité esto para depurar la declaración SQL generada en Entity Framework Core 2.1, así que uso DebugLoggerProvider o ConsoleLoggerProvider así:

[Fact] public async Task MyAwesomeTest { //setup log to debug sql queries var loggerFactory = new LoggerFactory(); loggerFactory.AddProvider(new DebugLoggerProvider()); loggerFactory.AddProvider(new ConsoleLoggerProvider(new ConsoleLoggerSettings())); var builder = new DbContextOptionsBuilder<DbContext>(); builder .UseSqlServer("my connection string") //"Server=.;Initial Catalog=TestDb;Integrated Security=True" .UseLoggerFactory(loggerFactory); var dbContext = new DbContext(builder.Options); ........

Aquí hay una salida de muestra de la consola de Visual Studio:


Hay dos maneras:

  1. Para ver el SQL que se generará, simplemente llame a ToTraceString() . Puede agregarlo a su ventana de visualización y establecer un punto de interrupción para ver cuál sería la consulta en cualquier momento para cualquier consulta LINQ.
  2. Puede adjuntar un marcador a su servidor SQL de elección, que le mostrará la consulta final en todos sus detalles sangrientos. En el caso de MySQL, la forma más fácil de rastrear las consultas es simplemente seguir el registro de consultas con tail -f . Puede obtener más información sobre las instalaciones de registro de MySQL en la documentación oficial . Para SQL Server, la forma más sencilla es utilizar el generador de perfiles de SQL Server incluido.

Mi respuesta se dirige a EF core . Hago referencia a este problema de github , y los documentos sobre la configuración de DbContext :

Sencillo

Sobrescriba el método OnConfiguring de su clase DbContext ( YourCustomDbContext ) como se muestra aquí para usar un ConsoleLoggerProvider; sus consultas deben iniciar sesión en la consola:

public class YourCustomDbContext : DbContext { #region DefineLoggerFactory public static readonly LoggerFactory MyLoggerFactory = new LoggerFactory(new[] {new ConsoleLoggerProvider((_, __) => true, true)}); #endregion #region RegisterLoggerFactory protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => optionsBuilder .UseLoggerFactory(MyLoggerFactory); // Warning: Do not create a new ILoggerFactory instance each time #endregion }

Complejo

Este caso complejo evita anular el método DbContext OnConfiguring . , que no se recomienda en los documentos: "Este enfoque no se presta a pruebas, a menos que las pruebas se dirijan a la base de datos completa".

Este caso complejo utiliza:

  • El IServiceCollection en la clase Startup ConfigureServices (en lugar de anular el método OnConfiguring ; el beneficio es un acoplamiento más flexible entre DbContext y el ILoggerProvider que desea usar)
  • Una implementación de ILoggerProvider (en lugar de usar la implementación de ConsoleLoggerProvider muestra arriba; la ventaja es que nuestra implementación muestra cómo nos registraríamos en un archivo (no veo un proveedor de registro de archivos incluido con EF Core ))

Me gusta esto:

public class Startup public void ConfigureServices(IServiceCollection services) { ... var lf = new LoggerFactory(); lf.AddProvider(new MyLoggerProvider()); services.AddDbContext<YOUR_DB_CONTEXT>(optionsBuilder => optionsBuilder .UseSqlServer(connection_string) //Using the LoggerFactory .UseLoggerFactory(lf)); ... } }

Aquí está la implementación de un MyLoggerProvider (y su MyLogger que agrega sus registros a un archivo que puede configurar; sus consultas de EF Core aparecerán en el archivo).

public class MyLoggerProvider : ILoggerProvider { public ILogger CreateLogger(string categoryName) { return new MyLogger(); } public void Dispose() { } private class MyLogger : ILogger { public bool IsEnabled(LogLevel logLevel) { return true; } public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter) { File.AppendAllText(@"C:/temp/log.txt", formatter(state, exception)); Console.WriteLine(formatter(state, exception)); } public IDisposable BeginScope<TState>(TState state) { return null; } } }


Nigromancia.
Esta página es el primer resultado de búsqueda cuando se busca una solución para cualquier .NET Framework, así que aquí como un servicio público, cómo se hace en EntityFramework Core (para .NET Core 1 y 2):

var someQuery = ( from projects in _context.projects join issues in _context.issues on projects.Id equals issues.ProjectId into tmpMapp from issues in tmpMapp.DefaultIfEmpty() select issues ) //.ToList() ; // string sql = someQuery.ToString(); // string sql = Microsoft.EntityFrameworkCore.IQueryableExtensions.ToSql(someQuery); // string sql = Microsoft.EntityFrameworkCore.IQueryableExtensions1.ToSql(someQuery); // using Microsoft.EntityFrameworkCore; string sql = someQuery.ToSql(); System.Console.WriteLine(sql);

Y luego estos métodos de extensión (IQueryableExtensions1 para .NET Core 1.0, IQueryableExtensions para .NET Core 2.0):

using System; using System.Linq; using System.Reflection; using Microsoft.EntityFrameworkCore.Internal; using Microsoft.EntityFrameworkCore.Query; using Microsoft.EntityFrameworkCore.Query.Internal; using Microsoft.EntityFrameworkCore.Storage; using Remotion.Linq.Parsing.Structure; namespace Microsoft.EntityFrameworkCore { // https://.com/questions/1412863/how-do-i-view-the-sql-generated-by-the-entity-framework // http://rion.io/2016/10/19/accessing-entity-framework-core-queries-behind-the-scenes-in-asp-net-core/ public static class IQueryableExtensions { private static readonly TypeInfo QueryCompilerTypeInfo = typeof(QueryCompiler).GetTypeInfo(); private static readonly FieldInfo QueryCompilerField = typeof(EntityQueryProvider).GetTypeInfo().DeclaredFields .First(x => x.Name == "_queryCompiler"); private static readonly PropertyInfo NodeTypeProviderField = QueryCompilerTypeInfo.DeclaredProperties.Single(x => x.Name == "NodeTypeProvider"); private static readonly MethodInfo CreateQueryParserMethod = QueryCompilerTypeInfo.DeclaredMethods.First(x => x.Name == "CreateQueryParser"); private static readonly FieldInfo DataBaseField = QueryCompilerTypeInfo.DeclaredFields.Single(x => x.Name == "_database"); private static readonly PropertyInfo DatabaseDependenciesField = typeof(Database).GetTypeInfo().DeclaredProperties.Single(x => x.Name == "Dependencies"); public static string ToSql<TEntity>(this IQueryable<TEntity> query) where TEntity : class { if (!(query is EntityQueryable<TEntity>) && !(query is InternalDbSet<TEntity>)) { throw new ArgumentException("Invalid query"); } var queryCompiler = (QueryCompiler) QueryCompilerField.GetValue(query.Provider); var nodeTypeProvider = (INodeTypeProvider) NodeTypeProviderField.GetValue(queryCompiler); var parser = (IQueryParser) CreateQueryParserMethod.Invoke(queryCompiler, new object[] {nodeTypeProvider}); var queryModel = parser.GetParsedQuery(query.Expression); var database = DataBaseField.GetValue(queryCompiler); var databaseDependencies = (DatabaseDependencies) DatabaseDependenciesField.GetValue(database); var queryCompilationContext = databaseDependencies.QueryCompilationContextFactory.Create(false); var modelVisitor = (RelationalQueryModelVisitor) queryCompilationContext.CreateQueryModelVisitor(); modelVisitor.CreateQueryExecutor<TEntity>(queryModel); var sql = modelVisitor.Queries.First().ToString(); return sql; } } public class IQueryableExtensions1 { private static readonly TypeInfo QueryCompilerTypeInfo = typeof(QueryCompiler).GetTypeInfo(); private static readonly FieldInfo QueryCompilerField = typeof(EntityQueryProvider).GetTypeInfo() .DeclaredFields .First(x => x.Name == "_queryCompiler"); private static readonly PropertyInfo NodeTypeProviderField = QueryCompilerTypeInfo.DeclaredProperties.Single(x => x.Name == "NodeTypeProvider"); private static readonly MethodInfo CreateQueryParserMethod = QueryCompilerTypeInfo.DeclaredMethods.First(x => x.Name == "CreateQueryParser"); private static readonly FieldInfo DataBaseField = QueryCompilerTypeInfo.DeclaredFields.Single(x => x.Name == "_database"); private static readonly FieldInfo QueryCompilationContextFactoryField = typeof(Database).GetTypeInfo() .DeclaredFields.Single(x => x.Name == "_queryCompilationContextFactory"); public static string ToSql<TEntity>(IQueryable<TEntity> query) where TEntity : class { if (!(query is EntityQueryable<TEntity>) && !(query is InternalDbSet<TEntity>)) { throw new ArgumentException("Invalid query"); } var queryCompiler = (IQueryCompiler) QueryCompilerField.GetValue(query.Provider); var nodeTypeProvider = (INodeTypeProvider) NodeTypeProviderField.GetValue(queryCompiler); var parser = (IQueryParser) CreateQueryParserMethod.Invoke(queryCompiler, new object[] {nodeTypeProvider}); var queryModel = parser.GetParsedQuery(query.Expression); var database = DataBaseField.GetValue(queryCompiler); var queryCompilationContextFactory = (IQueryCompilationContextFactory) QueryCompilationContextFactoryField.GetValue(database); var queryCompilationContext = queryCompilationContextFactory.Create(false); var modelVisitor = (RelationalQueryModelVisitor) queryCompilationContext.CreateQueryModelVisitor(); modelVisitor.CreateQueryExecutor<TEntity>(queryModel); var sql = modelVisitor.Queries.First().ToString(); return sql; } } }


Para aquellos que usan Entity Framework 6 en adelante, si desea ver el resultado de SQL en Visual Studio (como lo hice yo), debe usar la nueva funcionalidad de registro / intercepción.

La adición de la siguiente línea escupirá el SQL generado (junto con detalles adicionales relacionados con la ejecución) en el panel de resultados de Visual Studio:

using (MyDatabaseEntities context = new MyDatabaseEntities()) { context.Database.Log = s => System.Diagnostics.Debug.WriteLine(s); // query the database using EF here. }

Más información sobre el inicio de sesión en EF6 en esta ingeniosa serie de blogs: http://blog.oneunicorn.com/2013/05/08/ef6-sql-logging-part-1-simple-logging/

Nota: asegúrese de que está ejecutando su proyecto en modo DEBUG.


Para mí, utilizando EF6 y Visual Studio 2015 ingresé la query en la ventana inmediata y me dio la declaración SQL generada


Para tener la consulta siempre a mano, sin cambiar el código, agregue esto a su DbContext y verifíquelo en la ventana de resultados en Visual Studio.

protected override void OnModelCreating(DbModelBuilder modelBuilder) { Database.Log = (query)=> Debug.Write(query); }

Similar a la respuesta de @Matt Nibecker, pero con esto no tiene que agregarlo en su código actual, cada vez que necesite la consulta.


Puedes hacer lo siguiente en EF 4.1:

var result = from x in appEntities where x.id = 32 select x; System.Diagnostics.Trace.WriteLine(result .ToString());

Eso te dará el SQL que se generó.


Puedes hacer lo siguiente:

IQueryable query = from x in appEntities where x.id = 32 select x; var sql = ((System.Data.Objects.ObjectQuery)query).ToTraceString();

o en EF6:

var sql = ((System.Data.Entity.Core.Objects.ObjectQuery)query) .ToTraceString();

Eso te dará el SQL que se generó.


Si desea tener valores de parámetros (no solo @p_linq_0 sino también sus valores), puede usar IDbCommandInterceptor y agregar algún registro al método ReaderExecuted .


Si está utilizando un DbContext, puede hacer lo siguiente para obtener el SQL:

var result = from i in myContext.appEntities select new Model { field = i.stuff, }; var sql = result.ToString();


IQueryable query = from x in appEntities where x.id = 32 select x; var queryString = query.ToString();

Volverá la consulta sql. Trabajando usando datacontext de EntityFramework 6