Wie kann ich das vom Entity Framework generierte SQL anzeigen?
(In meinem speziellen Fall verwende ich den mysql-Anbieter - falls das eine Rolle spielt)
Wie kann ich das vom Entity Framework generierte SQL anzeigen?
(In meinem speziellen Fall verwende ich den mysql-Anbieter - falls das eine Rolle spielt)
Ich tue Integrationstest, und brauchte dies, um die generierte SQL-Anweisung in Entity Framework Core 2.1 zu debuggen, so dass ich verwenden DebugLoggerProvider
o ConsoleLoggerProvider
etwa so:
[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);
........
Hier ist eine Beispielausgabe der Visual Studio-Konsole:
SQL Management Studio => Werkzeuge => SQL Server Profiler
Datei => Neuer Trace...
Verwenden Sie die Vorlage => Blank
Ereignisauswahl => T-SQL
Linksseitige Prüfung auf: SP.StmtComplete
Spaltenfilter können verwendet werden, um einen bestimmten Anwendungsnamen oder Datenbanknamen auszuwählen.
Starten Sie dieses Profil und lösen Sie dann die Abfrage aus.
Klicken Sie hier für Informationen zur Quelle
Es gibt hier zwar gute Antworten, aber keine hat mein Problem vollständig gelöst (ich wollte die gesamte SQL-Anweisung erhalten), einschließlich Parameter aus dem DbContext von einem beliebigen IQueryable. Der folgende Code tut genau das. Es ist eine Kombination von Codeschnipseln von Google. Ich habe es nur mit EF6+ getestet. .
Nebenbei bemerkt hat mich diese Aufgabe viel länger beschäftigt, als ich dachte. Abstraktion in Entity Framework ist ein bisschen viel, IMHO.
Zuerst die Verwendung. Sie benötigen einen expliziten Verweis auf '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;
Die folgende Klasse wandelt eine IQueryable in eine DataTable um. Ändern Sie sie je nach Bedarf:
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;
foreach (var p in Parameters)
{
var param = cmd.CreateParameter();
param.Name = "@" + p.Name;
param.Value = p.Value;
cmd.Parameters.Add(param);
}
using (var da = DbProviderFactories.GetFactory(connection).CreateDataAdapter())
{
da.SelectCommand = cmd;
da.Fill(dt);
}
}
if (!(state == ConnectionState.Open))
connection.Close();
return dt;
}
}
Rufen Sie sie einfach wie folgt auf:
var context = new MyContext();
var data = ....//Query, return type can be anonymous
.AsQueryable();
var dt = new EntityFrameworkCommand()
.Initialize(context, data)
.GetData();
Entity Framework Core gibt SQL über das Logging-System aus. Es gibt nur ein paar kleine Tricks. Sie müssen eine ILoggerFactory
und Sie müssen einen Filter angeben. Hier ist ein Beispiel aus dieser Artikel
Erstellen Sie die Fabrik:
var loggerFactory = LoggerFactory.Create(builder =>
{
builder
.AddConsole((options) => { })
.AddFilter((category, level) =>
category == DbLoggerCategory.Database.Command.Name
&& level == LogLevel.Information);
});
Sag dem DbContext
um die Fabrik in der OnConfiguring
Methode:
optionsBuilder.UseLoggerFactory(_loggerFactory);
Von hier aus können Sie die Log-Methode nutzen, um Details über das ausgeführte SQL zu extrahieren. In diesem Artikel finden Sie eine ausführliche Diskussion.
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
}
CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.