¿Cómo veo el SQL generado por Entity Framework?
Frecuentes
Visto 362,868 veces
678
¿Cómo veo el SQL generado por el marco de la entidad?
(En mi caso particular, estoy usando el proveedor de mysql, si importa)
22 Respuestas
495
Puede 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 le dará el SQL que se generó.
Respondido el 30 de enero de 20 a las 10:01
No obtendrá SQL para consultas que terminen en .Single (), .Count (), .Any (), etc. de esa manera. - elástico76
Eso es porque despues de correr .Single()
tu objeto ya no es IQueryable
Supongo. - Suhas
con EF6, podría obtenerlo solo con reflexión. pero primero tuve que convertir result
a System.Data.Entity.Infrastructure.DbQuery<T>
, luego obtén la propiedad interna InternalQuery
as (System.Data.Entity.Internal.Linq.InternalQuery<T>)
, y solo entonces, usa ToTraceString()
- essho
agregar referencia a System.Data.Entity, System.Data.Objects.ObjectQuery existe en el dll anterior - Mahesh
En EF6 puedes simplemente hacer result.ToString()
- scott chambelán
1014
Para aquellos que usan Entity Framework 6 en adelante, si desea ver el SQL de salida en Visual Studio (como lo hice yo), debe usar la nueva funcionalidad de registro / intercepción.
Agregar la siguiente línea escupirá el SQL generado (junto con detalles adicionales relacionados con la ejecución) en el panel de salida 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 cómo iniciar 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.
Respondido 03 Abr '16, 17:04
Esta respuesta merece más amor (si está usando EF6 +) - gran adición de depuración, simplemente agréguela en el constructor DBContext (this.Database.Log = ...) - keithl8041
Asegúrese de que está ejecutando su proyecto en MODO DEPURACIÓN, verifique si el elemento "Depurar" se ha seleccionado en el cuadro combinado del panel Salida y también verifique si su depuración no se redirige a Inmediato (Herramientas> Opciones> Depuración> Redirigir todo el texto de la ventana de salida a Inmediato Ventana) - rkawano
¿Hay alguna manera de hacer que esto incluya los valores de las variables directamente dentro del sql generado? Un poco de dolor con los más grandes. - chris owens
@Matt Nibecker Esto no funciona en EF Core. ¿Cuál es la alternativa para EF Core? - nam
ADVERTENCIA: implementé esto con la intención de que solo se ejecute en desarrollo. Cuando lo implementamos en nuestro entorno de prueba, comenzamos a ver repentinamente pérdidas de memoria en el proceso de trabajo de IIS. Después de la generación de perfiles de memoria, nos dimos cuenta de que incluso GC explícito ya no recopilaba los objetos de contexto de la entidad (sí, estaban usando declaraciones). Al eliminar esta línea, todo volvió a la normalidad. Entonces, si bien esta es una gran herramienta, asegúrese de compilarla solo en su aplicación para el desarrollo. - brandon barkley
91
A partir de EF6.1, puede usar Interceptores para registrar un registrador de base de datos. Consulte los capítulos "Interceptores" y "Registro de operaciones de bases de datos" en un archivo. aquí
<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>
Respondido 07 Jul 14, 08:07
Publicación de blog sobre el tema blog.oneunicorn.com/2014/02/09/… - tim abel
Precisión, está por debajo de: ... - Cristóbal P.
85
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();
Respondido 02 Oct 13, 23:10
ToString()
le dará la consulta con variables en ella, como p__linq__0
, en lugar de los valores finales (por ejemplo: 34563 en lugar de p__linq__0
) - deportes
29
Aplicable para EF 6.0 y superior: para aquellos que quieran saber más sobre la funcionalidad de registro y agregar algunas de las respuestas ya dadas.
Ahora se puede registrar cualquier comando enviado desde EF a la base de datos. Para ver las consultas generadas desde EF 6.x, use el DBContext.Database.Log property
Qué 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í: Registro e interceptación de operaciones de bases de datos
Respondido 22 ago 16, 06:08
22
Puede 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 le dará el SQL que se generó.
Respondido el 01 de Septiembre de 11 a las 09:09
De hecho, creo que esto solo funciona cuando la consulta devuelve un tipo anónimo. Si devuelve un tipo personalizado, el ToString()
la salida es el espacio de nombres de ese tipo personalizado. Por ejemplo, si el código anterior fue select new CustomType { x = x.Name }
, el valor devuelto sería algo como Company.Models.CustomType
en lugar del SQL generado. - Chad Levy
Esta técnica produce System.Data.Objects.ObjectQuery``1[MyProject.Models.Product]
para mi. - Carlos G.
@CarlG System.Data.Objects.ObjectQuery no es EF 4.1 (DbContext). Usando DbContext sería System.Data.Entity.Infrastructure.DbQuery`1 [MyProject.Models.Product] que de hecho genera su SQL en una llamada a "ToString ()" - elástico76
Esto le dará el SQL que se generó, ¿dónde, en la ventana de salida? ¿Qué opción del menú desplegable? - JsonStatham
18
Mi respuesta se dirige a EF núcleo. Hago referencia a esto problema de githuby los documentos en Configurando DbContext
:
Sencillo
Anular el OnConfiguring
método de su DbContext
clase (YourCustomDbContext
) como se muestra aquí utilizar un ConsoleLoggerProvider; sus consultas deben registrarse 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 La DbContext
OnConfiguring
método. , que se desaconseja en los documentos: "Este enfoque no se presta a las pruebas, a menos que las pruebas se dirijan a la base de datos completa".
Este caso complejo utiliza:
- La
IServiceCollection
inStartup
claseConfigureServices
método (en lugar de anular elOnConfiguring
método; el beneficio es un acoplamiento más flojo entre elDbContext
yILoggerProvider
quieres usar) - Una implementación de
ILoggerProvider
(en lugar de usar elConsoleLoggerProvider
implementación mostrada arriba; El beneficio es que nuestra implementación muestra cómo registraríamos en el archivo (no veo un Proveedor de registro de archivos enviado con EF Core))
Me gusta:
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 es 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;
}
}
}
Respondido el 12 de junio de 18 a las 18:06
Entonces ... ¿no hay forma de hacerlo para principiantes? - Juan de la cruz
@JuanDelaCruz Simplifiqué mi respuesta; prueba la alternativa simple - El guisante rojo
Gracias por publicar esto. Me sorprendió que ya no haya una forma de hacerlo en la ventana inmediata en .NET Core. No quiero escribir código, solo quiero depurarlo. El generador de perfiles SQL es obviamente una opción, pero aún es más complicado de lo que solía ser. EGP
16
Hay dos maneras:
- Para ver el SQL que se generará, simplemente llame
ToTraceString()
. Puede agregarlo a su ventana de observación y establecer un punto de interrupción para ver cuál sería la consulta en cualquier punto dado para cualquier consulta LINQ. - Puede adjuntar un rastreador al servidor SQL de su elección, que le mostrará la consulta final con 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 funciones 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.
Respondido el 11 de Septiembre de 09 a las 20:09
¿El ToTraceString de qué? - nuestros
ObjectQuery, como señaló Nick justo después de que publiqué mi respuesta. - Benjamín Pollack
SQL Server Profiler captura los primeros 4000 caracteres, pero las consultas EF pueden ser mucho más largas. - usuario334911
14
Para tener la consulta siempre a mano, sin cambiar el código, agregue esto a su DbContext y verifíquelo en la ventana de salida 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.
Respondido el 21 de enero de 17 a las 18:01
¡La mejor respuesta! - AlexSC
12
EF Núcleo 5.0
¡Esta característica tan esperada está disponible en EF Core 5.0! Esto es del actualizaciones de estado semanales:
var query = context.Set<Customer>().Where(c => c.City == city); Console.WriteLine(query.ToQueryString())
da como resultado esta salida cuando se utiliza el proveedor de base de datos de SQL Server:
DECLARE p0 nvarchar(4000) = N'London'; SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] WHERE [c].[City] = @__city_0
Tenga en cuenta que las declaraciones para los parámetros del tipo correcto también se incluyen en la salida. Esto permite copiar / pegar en SQL Server Management Studio, o herramientas similares, de modo que la consulta se pueda ejecutar para depurar / analizar.
woohoo !!!
Respondido el 24 de junio de 20 a las 19:06
Este método no existe. - Christian Findlay
@ChristianFindlay aquí es la interfaz con el método y aquí es donde se incluye en EntityFrameworkQueryableExtensions. ¿Está utilizando EF Core 5.0? - josh blanco
¡buen punto! No. No es de extrañar que no pudiera verlo. Supongo que esto será en una versión preliminar de NuGet. - Christian Findlay
8
Estoy haciendo una prueba de integración y necesitaba esto para depurar la declaración SQL generada en Entity Framework Core 2.1, así que uso DebugLoggerProvider
or ConsoleLoggerProvider
al igual que:
[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:
Respondido 13 Oct 18, 06:10
DebugLoggerPrivider y ConsoleLoggerProvider parecen existir solo en .NET Core: docs.microsoft.com/en-us/dotnet/api/… - Gabriel Magaña
8
SQL Management Studio => Herramientas => Generador de perfiles de SQL Server
Archivo => Nueva traza ...
Use la Plantilla => En blanco
Selección de evento => T-SQL
Comprobación del lado izquierdo para: SP.StmtComplete
Los filtros de columna se pueden usar para seleccionar un ApplicationName o DatabaseName específico
Inicie ese perfil en ejecución y luego active la consulta.
Haga clic aquí para Información de origen
respondido 06 mar '19, 17:03
lo siento, eso es solo para el servidor SQL, no MySQL - andrew pate
6
IQueryable query = from x in appEntities
where x.id = 32
select x;
var queryString = query.ToString();
Devolverá la consulta SQL. Trabajando usando el contexto de datos de EntityFramework 6
Respondido 20 Oct 16, 08:10
Intenté esto y rastrea el objeto: Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable
1 [System.Linq.IGrouping2[System.Int32,String]]
en lugar de la consulta real. ¿Me estoy perdiendo algo o te olvidaste de mencionar algo? - loganjones16
5
Bueno, estoy usando Express Profiler para ese propósito en este momento, el inconveniente es que solo funciona para MS SQL Server. Puedes encontrar esta herramienta aquí: https://expressprofiler.codeplex.com/
Respondido el 23 de diciembre de 14 a las 09:12
5
Nigromante.
Esta página es el primer resultado de búsqueda cuando se busca una solución para cualquier .NET Framework, así que aquí, como servicio público, cómo se hace en EntityFrameworkCore (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://stackoverflow.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;
}
}
}
Respondido 13 Feb 18, 18:02
Estoy usando EF Core 2.0.1 y la sugerencia anterior da como resultado: System.InvalidCastException: 'No se puede lanzar un objeto de tipo Microsoft.EntityFrameworkCore.Query.Internal.InMemoryQueryModelVisitor' para escribir '' Microsoft.EntityFrameworkCore.Query.RelationalQueryModelVisitor'` para la línea: var modelVisitor = (RelationalQueryModelVisitor) queryCompilationContext.CreateQueryModelVisitor();
- Chris Wolf
@ChrisWolf si sigues la esencia del autor original, puedes encontrar a alguien que proporcionó una versión actualizada de ese método de extensión. Trabajó para mi. - B12 Tostadora
4
Utilice el registro con Entity Framework Core 3.x
Entity Framework Core emite SQL a través del sistema de registro. Solo hay un par de pequeños trucos. Debe especificar un ILoggerFactory
y debe especificar un filtro. Aquí hay un ejemplo de este artículo
Crea la fábrica:
var loggerFactory = LoggerFactory.Create(builder =>
{
builder
.AddConsole((options) => { })
.AddFilter((category, level) =>
category == DbLoggerCategory.Database.Command.Name
&& level == LogLevel.Information);
});
Di la DbContext
para usar la fábrica en el OnConfiguring
método:
optionsBuilder.UseLoggerFactory(_loggerFactory);
Desde aquí, puede volverse mucho más sofisticado y conectarse al método Log para extraer detalles sobre el SQL ejecutado. Vea el artículo para una discusión completa.
public class EntityFrameworkSqlLogger : ILogger
{
#region Fields
Action<EntityFrameworkSqlLogMessage> _logMessage;
#endregion
#region Constructor
public EntityFrameworkSqlLogger(Action<EntityFrameworkSqlLogMessage> logMessage)
{
_logMessage = logMessage;
}
#endregion
#region Implementation
public IDisposable BeginScope<TState>(TState state)
{
return default;
}
public bool IsEnabled(LogLevel logLevel)
{
return true;
}
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
if (eventId.Id != 20101)
{
//Filter messages that aren't relevant.
//There may be other types of messages that are relevant for other database platforms...
return;
}
if (state is IReadOnlyList<KeyValuePair<string, object>> keyValuePairList)
{
var entityFrameworkSqlLogMessage = new EntityFrameworkSqlLogMessage
(
eventId,
(string)keyValuePairList.FirstOrDefault(k => k.Key == "commandText").Value,
(string)keyValuePairList.FirstOrDefault(k => k.Key == "parameters").Value,
(CommandType)keyValuePairList.FirstOrDefault(k => k.Key == "commandType").Value,
(int)keyValuePairList.FirstOrDefault(k => k.Key == "commandTimeout").Value,
(string)keyValuePairList.FirstOrDefault(k => k.Key == "elapsed").Value
);
_logMessage(entityFrameworkSqlLogMessage);
}
}
#endregion
}
Respondido 20 Jul 20, 05:07
3
Para mí, usando EF6 y Visual Studio 2015 ingresé query
en la ventana inmediata y me dio la declaración SQL generada
Respondido 21 Jul 16, 16:07
No estoy seguro de por qué esto no se vota más a favor, esto es lo que funcionó para mí. - Codenova
2
En mi caso para EF 6+, en lugar de usar esto en la Ventana Inmediato 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ónima puede ser diferente.
HTH.
Respondido el 02 de Septiembre de 15 a las 19:09
2
Acabo de hacer esto:
IQueryable<Product> query = EntitySet.Where(p => p.Id == id);
Debug.WriteLine(query);
Y el resultado que se muestra en el 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
Respondido el 22 de junio de 16 a las 05:06
Sí, pero creo que nadie quiere ver el p__linq__i, pero los valores reales - tom stickel
De esta forma todavía funciona en EF 6 y será útil si solo le importa cómo se ve la estructura de la consulta. En mi caso el proyecto creo el IQueryable El objeto no tiene referencia a System.Data.Entity ni quiero agregarlo solo con fines de depuración. Entonces este método funcionó bien. - wctiger
2
Si bien hay buenas respuestas aquí, ninguna resolvió mi problema por completo (deseaba obtener la declaración SQL completa, incluyendo parámetros, desde DbContext desde cualquier IQueryable. El siguiente código hace precisamente eso. Es una combinación de fragmentos de código de Google. Solo lo he probado con EF6 +.
Solo un aparte, esta tarea me tomó mucho más tiempo de lo que pensé. La abstracción en Entity Framework es un poco excesiva, en mi humilde opinión.
Primero el uso. Necesitará una referencia explícita a 'System.Data.Entity.dll'.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data.SqlClient;
using System.Data.Common;
using System.Data.Entity.Core.Objects;
using System.Data.Entity;
using System.Data;
using System.Data.Entity.Infrastructure;
using System.Reflection;
La siguiente clase convierte un IQueryable en un DataTable. Modifique según su necesidad:
public class EntityFrameworkCommand
{
DbContext Context;
string SQL;
ObjectParameter[] Parameters;
public EntityFrameworkCommand Initialize<T>(DbContext context, IQueryable<T> query)
{
Context = context;
var dbQuery = query as DbQuery<T>;
// get the IInternalQuery internal variable from the DbQuery object
var iqProp = dbQuery.GetType().GetProperty("InternalQuery", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
var iq = iqProp.GetValue(dbQuery, null);
// get the ObjectQuery internal variable from the IInternalQuery object
var oqProp = iq.GetType().GetProperty("ObjectQuery", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
var objectQuery = oqProp.GetValue(iq, null) as ObjectQuery<T>;
SQL = objectQuery.ToTraceString();
Parameters = objectQuery.Parameters.ToArray();
return this;
}
public DataTable GetData()
{
DataTable dt = new DataTable();
var connection = Context.Database.Connection;
var state = connection.State;
if (!(state == ConnectionState.Open))
connection.Open();
using (var cmd = connection.CreateCommand())
{
cmd.CommandText = SQL;
cmd.Parameters.AddRange(Parameters.Select(p => new SqlParameter("@" + p.Name, p.Value)).ToArray());
using (var da = DbProviderFactories.GetFactory(connection).CreateDataAdapter())
{
da.SelectCommand = cmd;
da.Fill(dt);
}
}
if (!(state == ConnectionState.Open))
connection.Close();
return dt;
}
}
Para usarlo, simplemente llámelo de la siguiente manera:
var context = new MyContext();
var data = ....//Query, return type can be anonymous
.AsQueryable();
var dt = new EntityFrameworkCommand()
.Initialize(context, data)
.GetData();
Respondido el 29 de enero de 20 a las 18:01
Gran respuesta En lugar de new SqlParameter
, Deberías usar DbProviderFactories.GetFactory(connection).CreateParameter()
para que sea compatible con otros proveedores de bases de datos. - FKDev
0
Si desea tener valores de parámetro (no solo @p_linq_0
sino también sus valores), puedes usar IDbCommandInterceptor
y agregue algunos registros a ReaderExecuted
método.
Respondido el 27 de enero de 17 a las 11:01
0
Solución Entity Framework 4
La mayoría de las respuestas aquí fueron específicas de EF6. Aquí hay uno para aquellos de ustedes que todavía usan EF4.
Este método reemplaza el @p__linq__0
/ etc. parámetros con sus valores reales, por lo que puede copiar y pegar el resultado en SSMS y ejecutarlo o depurarlo.
/// <summary>
/// Temporary debug function that spits out the actual SQL query LINQ is generating (with parameters)
/// </summary>
/// <param name="q">IQueryable object</param>
private string Debug_GetSQLFromIQueryable<T>(IQueryable<T> q)
{
System.Data.Objects.ObjectQuery oq = (System.Data.Objects.ObjectQuery)q;
var result = oq.ToTraceString();
List<string> paramNames = new List<string>();
List<string> paramVals = new List<string>();
foreach (var parameter in oq.Parameters)
{
paramNames.Add(parameter.Name);
paramVals.Add(parameter.Value == null ? "NULL" : ("'" + parameter.Value.ToString() + "'"));
}
//replace params in reverse order, otherwise @p__linq__1 incorrectly replaces @p__linq__10 for instance
for (var i = paramNames.Count - 1; i >= 0; i--)
{
result = result.Replace("@" + paramNames[i], paramVals[i]);
}
return result;
}
contestado el 26 de mayo de 20 a las 05:05
No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas entity-framework ado.net or haz tu propia pregunta.
Este planteamiento de « artice de MSDN Magazine describe algunas opciones de creación de perfiles para Entity Framework 4: Arve
La pregunta "duplicada" vinculada es para LINQ to SQL, por lo que en realidad no es un duplicado. - jrummell
Cuando se ejecuta en el depurador, IntelliTrace muestra las consultas SQL realizadas, aunque sin sus resultados. - ivan_pozdeev
Si está interesado en ver SQL durante el desarrollo, puede usar LINQPad. Cuando ejecute una consulta LINQ en los resultados, habrá una pestaña SQL que muestra la instrucción SQL ejecutada. Para mySQL, tendrá que instalar un controlador. No tengo una base de datos mySQL disponible, pero debería funcionar. - gligoran