web-dev-qa-db-fra.com

Comment visualiser le code SQL généré par Entity Framework?

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)

564
nos

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é.

444
Nick Berardi

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.

884
Matt Nibecker

À 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>
77
isepise

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();
77
Doug Clutter

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

21
NullReference

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é.

18
Capriols

Il y a deux manières:

  1. Pour afficher le code SQL qui sera généré, appelez simplement 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.
  2. Vous pouvez attacher un traceur au serveur SQL de votre choix, qui vous montrera la requête finale dans tous ses détails sanglants. Dans le cas de MySQL, le moyen le plus simple de suivre les requêtes est tout simplement de personnaliser le journal des requêtes avec 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.
16
Benjamin Pollack

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 DbContextOnConfiguring. , 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:

  • La méthode 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)
  • Une implémentation de 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;
        }
    } 
}
11
The Red Pea

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.

6
Gerrie Pretorius

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/

5
VincentZHANG
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

5
Gianluca Conte

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:

Sample SQL statement output

4
Rosdi Kasim

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;
        }


    }


}
3
Stefan Steiger

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

3
andrew pate

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.

2
Jonas Stawski

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
2
Daniel Camargo

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.

2
user8128167

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.

1
jabko87