Varlık çerçevesi tarafından oluşturulan SQL'i nasıl görüntülerim?
(Benim özel durumumda mysql sağlayıcı kullanıyorum - önemliyse)
Varlık çerçevesi tarafından oluşturulan SQL'i nasıl görüntülerim?
(Benim özel durumumda mysql sağlayıcı kullanıyorum - önemliyse)
Yanıtlar:
Aşağıdakileri yapabilirsiniz:
IQueryable query = from x in appEntities
where x.id == 32
select x;
var sql = ((System.Data.Objects.ObjectQuery)query).ToTraceString();
veya EF6'da:
var sql = ((System.Data.Entity.Core.Objects.ObjectQuery)query)
.ToTraceString();
Bu size üretilen SQL'i verecektir.
.Single()
nesnenizi çalıştırdıktan sonra artık IQueryable
sanmıyorum.
result
için System.Data.Entity.Infrastructure.DbQuery<T>
, daha sonra iç özelliğini almak InternalQuery
olarak (System.Data.Entity.Internal.Linq.InternalQuery<T>)
ve ancak o zaman, kullanımToTraceString()
result.ToString()
Entity Framework 6 ve üstünü kullananlar için, Visual Studio'da (yaptığım gibi) çıktı SQL'ini görüntülemek istiyorsanız, yeni günlük / yakalama işlevini kullanmanız gerekir.
Aşağıdaki satırı eklemek, oluşturulan SQL (yürütme ile ilgili ek ayrıntılarla birlikte) Visual Studio çıktı panelinde tükürecektir:
using (MyDatabaseEntities context = new MyDatabaseEntities())
{
context.Database.Log = s => System.Diagnostics.Debug.WriteLine(s);
// query the database using EF here.
}
Bu şık blog serisinde EF6'ya giriş hakkında daha fazla bilgi: http://blog.oneunicorn.com/2013/05/08/ef6-sql-logging-part-1-simple-logging/
Not: Projenizi DEBUG modunda çalıştırdığınızdan emin olun.
EF6.1 ile başlayarak bir veritabanı kaydedicisini kaydetmek için Durdurucuları kullanabilirsiniz. Dosyaya "Müdahale" ve "Günlük Veritabanı İşlemleri" bölümlerine bakın burada
<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>
Bir DbContext kullanıyorsanız, SQL almak için aşağıdakileri yapabilirsiniz:
var result = from i in myContext.appEntities
select new Model
{
field = i.stuff,
};
var sql = result.ToString();
ToString()
size p__linq__0
son değerler yerine değişkenler içeren bir sorgu verecektir (örneğin: 34563 yerine p__linq__0
)
EF 6.0 ve üstü için geçerlidir: Günlük tutma işlevi hakkında daha fazla bilgi edinmek ve daha önce verilmiş olan bazı cevapları eklemek isteyenler için.
EF'den veritabanına gönderilen herhangi bir komut artık günlüğe kaydedilebilir. EF 6.x'ten oluşturulan sorguları görüntülemek içinDBContext.Database.Log property
Günlüğe Kaydedilenler
- 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.
Misal:
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();
}
Çıktı:
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
Harici bir dosyaya giriş yapmak için:
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();
}
}
Daha fazla bilgi için: Veritabanı İşlemlerini Günlüğe Kaydetme ve Durdurma
EF 4.1'de aşağıdakileri yapabilirsiniz:
var result = from x in appEntities
where x.id = 32
select x;
System.Diagnostics.Trace.WriteLine(result .ToString());
Bu size üretilen SQL'i verecektir.
ToString()
çıktı o özel türün ad alanıdır. Örneğin, yukarıdaki kod select new CustomType { x = x.Name }
olsaydı, döndürülen değer Company.Models.CustomType
üretilen SQL yerine benzer bir şey olurdu .
System.Data.Objects.ObjectQuery``1[MyProject.Models.Product]
benim için üretiyor .
Cevabım EF çekirdeğine hitap ediyor . Bu github sorununa ve yapılandırmaDbContext
belgelerine başvuruyorum :
Basit
ConsoleLoggerProvider'ı kullanmak için burada gösterildiği gibi class ( ) OnConfiguring
yönteminizi geçersiz kılın ; sorgularınız konsola giriş yapmalıdır:DbContext
YourCustomDbContext
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
}
karmaşık
Bu Karmaşık durum , yöntemin geçersiz kılınmasını önler .DbContext
OnConfiguring
, dokümanlarda önerilmiyor: "Testler tam veritabanını hedeflemedikçe bu yaklaşım teste kendini vermez."
Bu Karmaşık vaka şunları kullanır:
IServiceCollection
İçerisinde Startup
sınıf ConfigureServices
yöntemi (yerine geçersiz kılma OnConfiguring
yöntemi; yarar arasında gevşek bir bağlantı olan DbContext
veILoggerProvider
kullanmak isteyen)ILoggerProvider
( ConsoleLoggerProvider
yukarıda gösterilen uygulamayı kullanmak yerine , bizim uygulamamız Dosyaya nasıl giriş yapacağımızı gösterir ( EF Core ile birlikte gönderilen bir Dosya Günlüğü Sağlayıcısı göremiyorum )Bunun gibi:
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));
...
}
}
İşte bir MyLoggerProvider
(ve MyLogger
günlüklerini yapılandırabileceğiniz bir Dosyaya ekleyen uygulama ; EF Çekirdek sorgularınız dosyada görünecektir.)
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;
}
}
}
İki yol vardır:
ToTraceString()
. İzleme pencerenize ekleyebilir ve herhangi bir LINQ sorgusu için sorgunun herhangi bir noktada ne olacağını görmek için bir kesme noktası ayarlayabilirsiniz.tail -f
. MySQL'in kayıt tesisleri hakkında daha fazla bilgiyi resmi belgelerden öğrenebilirsiniz . SQL Server için, en kolay yol dahil edilen SQL Server profil oluşturucusunu kullanmaktır.Sorguyu her zaman kullanışlı hale getirmek için, kodu değiştirmeden bunu DbContext'inize ekleyin ve visual studio'daki çıkış penceresinde kontrol edin.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
Database.Log = (query)=> Debug.Write(query);
}
@Matt Nibecker cevabına benzer, ancak bununla sorguyu her ihtiyacınız olduğunda geçerli kodunuza eklemeniz gerekmez.
SQL Management Studio => Araçlar => SQL Server profili oluşturucu
Dosya => Yeni İzleme ...
Şablonu Kullan => Boş
Olay seçimi => T-SQL
Sol taraf kontrol: SP.StmtComplete
Sütun filtreleri belirli bir UygulamaAdı veya VeritabanıAdı seçmek için kullanılabilir
Çalışmakta olan profili başlatın, ardından sorguyu tetikleyin.
Kaynak bilgileri için buraya tıklayın
Eh, şu anda bu amaçla Express profiler kullanıyorum, dezavantajı sadece MS SQL Server için çalışıyor olmasıdır. Bu aracı burada bulabilirsiniz: https://expressprofiler.codeplex.com/
IQueryable query = from x in appEntities
where x.id = 32
select x;
var queryString = query.ToString();
Sql sorgusunu döndürür. EntityFramework 6 veri bağlamını kullanarak çalışma
Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable
1 [System.Linq.IGrouping 2[System.Int32,String]]
yerine gerçek sorgu. Bir şey mi kaçırıyorum yoksa bir şeyden bahsetmeyi unuttun mu?
Entegrasyon testi yapıyorum ve Entity Framework Core 2.1 oluşturulan SQL deyimi hata ayıklamak için gerekli, bu yüzden kullanmak DebugLoggerProvider
ya ConsoleLoggerProvider
da böyle:
[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);
........
İşte Visual Studio konsolundan bir örnek çıktı:
Necromancing.
Bu sayfa, herhangi bir .NET Framework için bir çözüm ararken ilk arama sonucudur, bu nedenle burada bir kamu hizmeti olarak, EntityFramework Core'da (.NET Core 1 ve 2 için) nasıl yapıldığı :
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);
Ve sonra bu uzantı yöntemleri (.NET Core 1.0 için IQueryableExtensions1, .NET Core 2.0 için IQueryableExtensions):
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
{
// /programming/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;
}
}
}
var modelVisitor = (RelationalQueryModelVisitor) queryCompilationContext.CreateQueryModelVisitor();
Benim durumumda EF 6+ için, bunu sorgu dizesini bulmak için Anında Penceresinde kullanmak yerine:
var sql = ((System.Data.Entity.Core.Objects.ObjectQuery)query).ToTraceString();
Ben oluşturulan SQL komutu almak için bunu kullanmak zorunda sona erdi:
var sql = ((System.Data.Entity.Infrastructure.DbQuery<<>f__AnonymousType3<string,string,string,short,string>>)query).ToString();
Elbette anonim tip imzanız farklı olabilir.
HTH.
Bunu yeni yaptım:
IQueryable<Product> query = EntitySet.Where(p => p.Id == id);
Debug.WriteLine(query);
Ve sonuç gösterilen Çıktı :
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
Benim için, EF6 ve Visual Studio 2015 kullanarak query
hemen pencereye girdim ve bana üretilen SQL İfadesini verdi
Parametre değerlerine (yalnızca değerlerine değil @p_linq_0
aynı zamanda değerlerine de) sahip olmak istiyorsanız, yönteme IDbCommandInterceptor
bazı günlükleri kullanabilir ve ekleyebilirsiniz ReaderExecuted
.
İyi cevaplar burada olsa da, hiçbiri tamamen benim sorunu (ben tüm SQL deyimi, almak istediği çözüldü Parametreleri içeren herhangi IQueryable dan DBContext gelen. Aşağıdaki kod O Google'dan kod parçacıkları bir kombinasyonudur sadece o. Yok. I sadece EF6 + ile test ettik .
Bir kenara, bu görev beni düşündüğümden çok daha uzun sürdü. Entity Framework'te soyutlama biraz fazla, IMHO.
Önce kullanma. 'System.Data.Entity.dll' için açık bir başvuruya ihtiyacınız olacaktır.
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;
Aşağıdaki sınıf bir IQueryable'ı DataTable'a dönüştürür. İhtiyacınız olabilecek şekilde değiştirin:
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;
}
}
Kullanmak için aşağıdaki gibi aramanız yeterlidir:
var context = new MyContext();
var data = ....//Query, return type can be anonymous
.AsQueryable();
var dt = new EntityFrameworkCommand()
.Initialize(context, data)
.GetData();
Buradaki cevapların çoğu EF6'ya özgüdür. İşte hala EF4 kullananlarınız için bir tane.
Bu yöntem @p__linq__0
/ etc yerine geçer . parametrelerini gerçek değerleriyle değiştirerek çıktıyı kopyalayıp SSMS'ye yapıştırabilir ve çalıştırabilir veya hata ayıklayabilirsiniz.
/// <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;
}