Comment visualiser le code SQL généré par la structure de l'entité?
(Dans mon cas, j'utilise le fournisseur mysql - si c'est important)
Vous pouvez faire ce qui suit:
IQueryable query = from x in appEntities
where x.id = 32
select x;
var sql = ((System.Data.Objects.ObjectQuery)query).ToTraceString();
ou en EF6:
var sql = ((System.Data.Entity.Core.Objects.ObjectQuery)query)
.ToTraceString();
Cela vous donnera le SQL qui a été généré.
Pour ceux qui utilisent Entity Framework 6 et versions supérieures, si vous souhaitez afficher le résultat SQL dans Visual Studio (comme je l'ai fait), vous devez utiliser la nouvelle fonctionnalité de journalisation/interception.
L'ajout de la ligne suivante créera le code SQL généré (avec des détails supplémentaires liés à l'exécution) dans le panneau de sortie de Visual Studio:
using (MyDatabaseEntities context = new MyDatabaseEntities())
{
context.Database.Log = s => System.Diagnostics.Debug.WriteLine(s);
// query the database using EF here.
}
Plus d'informations sur la connexion à EF6 dans cette série de blogs géniaux: http://blog.oneunicorn.com/2013/05/08/ef6-sql-logging-part-1-simple-logging/
Remarque: Assurez-vous d’exécuter votre projet en mode DEBUG.
À partir de EF6.1, vous pouvez utiliser Interceptors pour enregistrer un enregistreur de base de données. Voir les chapitres "Intercepteurs" et "Journalisation des opérations de base de données" dans un fichier ici
<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>
Si vous utilisez un DbContext, vous pouvez procéder comme suit pour obtenir le code SQL:
var result = from i in myContext.appEntities
select new Model
{
field = i.stuff,
};
var sql = result.ToString();
Applicable pour EF 6.0 et versions ultérieures: pour ceux d'entre vous qui veulent en savoir plus sur la fonctionnalité de journalisation et ajouter certaines des réponses déjà données.
Toute commande envoyée de l'EF à la base de données peut maintenant être enregistrée. Pour afficher les requêtes générées à partir de EF 6.x, utilisez le DBContext.Database.Log property
Ce qui est enregistré
- 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.
Exemple:
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();
}
Sortie:
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
Pour vous connecter à un fichier externe:
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();
}
}
Plus d'informations ici: Journalisation et interception des opérations de base de données
Vous pouvez effectuer les opérations suivantes dans EF 4.1:
var result = from x in appEntities
where x.id = 32
select x;
System.Diagnostics.Trace.WriteLine(result .ToString());
Cela vous donnera le SQL qui a été généré.
Il y a deux manières:
ToTraceString()
. Vous pouvez l'ajouter à votre fenêtre de surveillance et définir un point d'arrêt pour voir quelle serait la requête à un moment donné pour une requête LINQ.tail -f
. Pour en savoir plus sur les fonctions de journalisation de MySQL, consultez la documentation officielle . Pour SQL Server, le moyen le plus simple consiste à utiliser le profileur SQL Server inclus.Ma réponse concerne EF core . Je fais référence à ceci numéro de github , et à la documentation sur configuration de DbContext
:
Simple
Remplacez la méthode OnConfiguring
de votre classe DbContext
(YourCustomDbContext
) comme indiqué ici pour utiliser un ConsoleLoggerProvider; vos requêtes doivent se connecter à la console:
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
}
Complexe
Ce cas complexe évite de surcharger la méthode DbContext
OnConfiguring
. , déconseillée dans la documentation: "Cette approche ne se prête pas à un test, sauf si les tests visent la base de données complète. "
Ce cas complexe utilise:
IServiceCollection
in Startup
class ConfigureServices
(au lieu de remplacer la méthode OnConfiguring
; l'avantage est un couplage plus lâche entre DbContext
et ILoggerProvider
vous voulez utiliser)ILoggerProvider
(au lieu d’utiliser l’implémentation ConsoleLoggerProvider
ci-dessus; l’avantage de notre implémentation montre comment nous nous connecterions au fichier (je ne vois pas un fournisseur de journalisation de fichiers livré avec EF) Core ))Comme ça:
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));
...
}
}
Voici l'implémentation d'un MyLoggerProvider
(et de son MyLogger
qui ajoute ses journaux à un fichier que vous pouvez configurer; vos requêtes EF Core apparaîtront dans le fichier.)
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;
}
}
}
Pour que la requête soit toujours à portée de main, sans changer de code, ajoutez-le à votre DbContext et vérifiez-le dans la fenêtre de sortie de visual studio.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
Database.Log = (query)=> Debug.Write(query);
}
Similaire à @Matt Nibecker answer, mais vous n'avez pas besoin de l'ajouter à votre code actuel à chaque fois que vous avez besoin de la requête.
Bien, j’utilise Express profiler à cette fin pour le moment, l’inconvénient est que cela ne fonctionne que pour MS SQL Server. Vous pouvez trouver cet outil ici: https://expressprofiler.codeplex.com/
IQueryable query = from x in appEntities
where x.id = 32
select x;
var queryString = query.ToString();
Renverra la requête SQL. Travailler avec datacontext de EntityFramework 6
Je fais un test d'intégration et j'avais besoin de cela pour déboguer l'instruction SQL générée dans Entity Framework Core 2.1. J'utilise donc DebugLoggerProvider
ou ConsoleLoggerProvider
comme suit:
[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);
........
Voici un exemple de sortie de la console Visual Studio:
Nécromancie.
Cette page est le premier résultat de la recherche effectuée lors de la recherche d'une solution pour n'importe quel .NET Framework, donc ici, en tant que service public, comment cela se passe dans EntityFramework Core (pour .NET Core 1 & 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);
Et puis ces méthodes d'extension (IQueryableExtensions1 pour .NET Core 1.0, IQueryableExtensions pour .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;
}
}
}
SQL Management Studio => Outils => Profileur SQL Server
Fichier => Nouvelle trace ...
Utilisez le modèle => Blank
Sélection d'événements => T-SQL
Vérification à gauche pour: SP.StmtComplete
Les filtres de colonne peuvent être utilisés pour sélectionner un nom d'application ou un nom de base de données spécifique
Démarrer ce profil en cours d'exécution puis déclencher la requête.
Cliquez ici pour informations de source
Pour moi, en utilisant EF6 et Visual Studio 2015, j'ai entré query
dans la fenêtre immédiate et cela m'a donné l'instruction SQL générée.
Je viens de faire ceci:
IQueryable<Product> query = EntitySet.Where(p => p.Id == id);
Debug.WriteLine(query);
Et le résultat affiché dans le Sortie:
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
Dans mon cas pour EF 6+, au lieu de l’utiliser dans la fenêtre Immediate pour trouver la chaîne de requête:
var sql = ((System.Data.Entity.Core.Objects.ObjectQuery)query).ToTraceString();
J'ai fini par devoir utiliser ceci pour obtenir la commande SQL générée:
var sql = ((System.Data.Entity.Infrastructure.DbQuery<<>f__AnonymousType3<string,string,string,short,string>>)query).ToString();
Bien entendu, votre signature de type anonyme peut être différente.
HTH.
Si vous souhaitez également avoir des valeurs de paramètre (non seulement @p_linq_0
, mais également leurs valeurs), vous pouvez utiliser IDbCommandInterceptor
et ajouter des traces à la méthode ReaderExecuted
.