web-dev-qa-db-fra.com

Comment enregistrer des requêtes à l'aide d'Entity Framework 7?

J'utilise Entity Framework 7 sur le canal de construction nocturne (j'utilise actuellement la version EntityFramework.7.0.0-beta2-11524) et j'essaie de consigner les requêtes générées par EF simplement par curiosité.

J'écris un programme console simple, j'ai essayé d'utiliser la technique de journalisation même utilisée par EF6, mais DbContext.Database.Log n'est pas disponible sur Entity Framework 7. Existe-t-il un moyen de se connecter ou de jeter un coup d'œil au code SQL généré? par EF7?

13
Mahmoud Ali

Pour ceux qui utilisent EF7, rien de ce qui précède n'a fonctionné pour moi. Mais voici comment je le fais fonctionner. (du commentaire de @avi cherry)

Dans votre Startup.cs , vous avez probablement une méthode Configure avec un tas de configurations. Cela devrait ressembler à ce qui suit (en plus de vos affaires).

    public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
    {
        //this is the magic line
        loggerFactory.AddDebug(LogLevel.Debug); // formerly LogLevel.Verbose

        //your other stuff

    }
8
BobbyTables

Vous pouvez vous connecter à la console en utilisant ce code, je suis sûr qu'il sera enveloppé dans une API plus simple plus tard:

using System;
using Microsoft.Data.Entity.Infrastructure;
using Microsoft.Data.Entity.Utilities;
using Microsoft.Framework.Logging;

public static class SqlCeDbContextExtensions
{
    public static void LogToConsole(this DbContext context)
    {
        var loggerFactory = ((IAccessor<IServiceProvider>)context).GetService<ILoggerFactory>();
        loggerFactory.AddProvider(new DbLoggerProvider());
    }
}

Et DbLoggerProvider est implémenté ici: https://github.com/ErikEJ/EntityFramework7.SqlServerCompact/tree/master/src/Provider40/Extensions/Logging

7
ErikEJ

J'ai eu du mal avec toutes les réponses ci-dessus, car les bits EF continuaient à changer, ainsi le code ne serait pas compilé. À compter d'aujourd'hui (19 février 2015) avec EF7.0.0-rc1-final (Prerelease) et SQLite, voici ce qui fonctionne pour moi:

De la documentation EF7:

using System;
using System.IO;
using Microsoft.Extensions.Logging;

namespace EFLogging
{
    public class EFLoggerProvider : ILoggerProvider
    {
        public ILogger CreateLogger(string categoryName)
        {
            return new EFLogger();
        }

        public void Dispose()
        {
            // N/A
        }

        private class EFLogger : ILogger
        {
            public IDisposable BeginScopeImpl(object state)
            {
                return null;
            }

            public bool IsEnabled(LogLevel logLevel)
            {
                return true;
            }

            public void Log(LogLevel logLevel, int eventId, object state, Exception exception, Func<object, Exception, string> formatter)
            {
                File.AppendAllText(@".\EF.LOG", formatter(state, exception));
                Console.WriteLine(formatter(state, exception));
            }
        }
    }
}

En utilisant quelques idées ci-dessus et les documents EF7:

using System;
using Microsoft.Data.Entity;
using Microsoft.Data.Entity.Infrastructure;
using Microsoft.Extensions.DependencyInjection;  // Add this to EF7 docs code
using Microsoft.Extensions.Logging;

namespace DataAccessLayer
{
    public static class DbContextExtensions
    {
        public static void LogToConsole(this DbContext context)
        {
            var serviceProvider = context.GetInfrastructure<IServiceProvider>();
            var loggerFactory = serviceProvider.GetService<ILoggerFactory>();
            loggerFactory.AddProvider(new EFLoggerProvider(logLevel));
        }
    }
}

EDIT: @ jnm2 a souligné si vous ajoutez "using Microsoft.Extensions.DependencyInjection", les documents EF7 SONT corrects. Merci!

Et enfin, dans ma méthode App.OnStartup:

using (var db = new MyDbContext())
{
    db.LogToConsole();
}

Ce code crée un fichier journal et génère également des informations de journalisation dans la fenêtre de sortie de Visual Studio. J'espère que cela aide - je suis sûr que dans quelques semaines, les bits vont changer à nouveau.

5
RandyB

Avec la dernière version de EF7-beta8, la réponse d'Anthony doit être légèrement modifiée. Voici ce que j'ai fait pour que cela fonctionne.

internal static class DbContextExtensions
{
    public static void LogToConsole(this DbContext context)
    {
        var loggerFactory = context.GetService<ILoggerFactory>();
        loggerFactory.AddConsole(LogLevel.Verbose);
    }
}
4
Tyler

Si vous utilisez MS SQL Server , l’une des méthodes que j’ai utilisées par le passé est d’utiliser le SQL Server Profiler et de capturer toutes les interactions avec SQL Server. Il s’agit de saisir le code SQL exact soumis. et peut être coupé n collé dans SQL Server Management Studio pour un examen ultérieur. Je sais que cela ne répond pas directement à votre question sur Entity Framework, mais j’ai trouvé cette approche générique très utile pour toute langue/outils.

Une astuce se trouve dans les propriétés de la trace lors de la configuration d’une nouvelle trace, il m’a semblé utile d’ajuster la sélection d’événements par défaut dans l’onglet Sélection des événements. Généralement, je désactive la connexion à l'audit/la déconnexion, sauf si un problème de ce type est détecté.

4
miltonb

Je pense que j'ai compris cela. Avec les bits EF7 actuels, ILoggerFactory est enregistré avec le conteneur d'injection de dépendance utilisé par EF. Vous pouvez obtenir une référence au conteneur, qui est un IServiceProvider, via la propriété ScopedServiceProvider de DbContext lorsqu'il est converti en IDbContextServices. À partir de là, vous pouvez obtenir ILoggerFactory et le configurer à l'aide de la méthode d'extension AddToConsole du package Microsoft.Framework.Logging.Console NuGet.

public static void LogToConsole(this DbContext context)
{
    // IServiceProvider represents registered DI container
    IServiceProvider contextServices = ((IDbContextServices)context).ScopedServiceProvider;

    // Get the registered ILoggerFactory from the DI container
    var loggerFactory = contextServices.GetRequiredService<ILoggerFactory>();

    // Add a logging provider with a console trace listener
    loggerFactory.AddConsole(LogLevel.Verbose);
}

Voici un Gist que j'ai créé pour cet extrait: https://Gist.github.com/tonysneed/4cac4f4dae2b22e45ec4

3
Anthony Sneed

Avec ASP.NET Core 2.0 vous obtenez automatiquement la journalisation SQL . Pas besoin de faire quelque chose de plus.

2
grokky

Cela a fonctionné pour moi avec EF7 rc2-16485:

"EntityFramework.MicrosoftSqlServer": "7.0.0-rc2-16485",
"Microsoft.Extensions.Logging.Console": "1.0.0-rc2-15888",

public static class DbContextExtensions
{
    public static void LogToConsole(this DbContext context)
    {
        var contextServices = ((IInfrastructure<IServiceProvider>) context).Instance;
        var loggerFactory = contextServices.GetRequiredService<ILoggerFactory>();
        loggerFactory.AddConsole(LogLevel.Verbose);
    }
}
2
Flynn

En guise d'alternative aux réponses ci-dessus, j'ai trouvé cette réponse de loin la solution la plus simple pour moi de raisonner à propos de:

private readonly ILoggerFactory loggerFactory;

// Using dependency injection
public FooContext(ILoggerFactory loggerFactor) {
    this.loggerFactory = loggerFactory;
}

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {
    optionsBuilder.UseLoggerFactory(loggerFactory);    // Register logger in context
}
1
Matt