Entity Framework tarafından oluşturulan SQL'i nasıl görüntülerim?


624

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)


1
MSDN Magazine'in bu eseri Entity Framework 4 için bazı profilleme seçeneklerini açıklıyor
Arve

2
Bağlantılı "yinelenen" soru LINQ to SQL içindir, bu yüzden aslında bir yinelenen değil.
jrummell

2
Hata ayıklayıcı altında çalışırken IntelliTrace, sonuçları olmasa da yapılan SQL sorgularını gösterir.
ivan_pozdeev

SQL'i geliştirme sırasında görmek istiyorsanız, LINQPad kullanabilirsiniz . Sonuçlarda bir LINQ sorgusu çalıştırdığınızda yürütülen SQL deyimini gösteren bir SQL sekmesi olacaktır. MySQL için bir sürücü yüklemeniz gerekir. Kullanılabilir bir mySQL veritabanım yok, ancak çalışması gerekiyor.
gligoran

Yanıtlar:


472

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.


20
Bu şekilde .Single (), .Count (), .Any () vb. İle biten sorgular için SQL almazsınız.
springy76

24
Çünkü .Single()nesnenizi çalıştırdıktan sonra artık IQueryablesanmıyorum.
Suhas

11
EF6 ile, sadece yansımayla alabilirim. ama önce dönüştürmek zorunda resultiçin System.Data.Entity.Infrastructure.DbQuery<T>, daha sonra iç özelliğini almak InternalQueryolarak (System.Data.Entity.Internal.Linq.InternalQuery<T>)ve ancak o zaman, kullanımToTraceString()
itsho

9
Yukarıdaki dll
Mahesh

54
EF6'da şunları yapabilirsinizresult.ToString()
Scott Chamberlain

956

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.


107
Bu yanıt daha fazla aşkı hak ediyor (EF6 + kullanıyorsanız) - büyük hata ayıklama eklentisi, DBContext yapıcısına ekleyin (this.Database.Log = ...)
keithl8041

21
Projenizi DEBUG MODE'da çalıştırdığınızdan emin olun, Çıktı bölmesinin birleşik kutusunda "Hata Ayıkla" öğesinin seçili olup olmadığını kontrol edin ve ayrıca hata ayıklamanızın Hemen yönlendirilip yönlendirilmediğini kontrol edin (Araçlar> Seçenekler> Hata Ayıklama> Tüm Çıktı Penceresi metnini Hemen Yeniden Yönlendir Pencere)
rkawano

5
değişken değerleri doğrudan oluşturulan sql içine dahil etmek için bir yolu var mı? Büyük olanlarla biraz acı.
Chris

22
@Matt Nibecker EF Core'da çalışmaz. EF Core'un alternatifi nedir?
nam

9
UYARI: Bunu sadece geliştirme aşamasında olmak amacıyla uyguladım. Test ortamımıza konuşlandırdığımızda, IIS Çalışan İşleminde bellek sızıntılarını aniden görmeye başladık. Bellek profillemesinden sonra, açıkça GC'nin artık varlık bağlam nesnelerini toplamadığını fark ettik (evet, ifadeler kullanıyordu). Bu satır kaldırıldığında hepsi normale döndü. Bu nedenle, bu harika bir araç olsa da, yalnızca geliştirme için uygulamanıza yerleştirdiğinizden emin olun.
Brandon Barkley

82

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>

1
Konuyla ilgili blog yazısı blog.oneunicorn.com/2014/02/09/…
Tim Abell

12
Hassasiyet, Altında: <configuration> <entityFramework> <interceptors> ... </interceptors> </entityFramework> </configuration>
Christophe P

80

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();

12
ToString()size p__linq__0son değerler yerine değişkenler içeren bir sorgu verecektir (örneğin: 34563 yerine p__linq__0)
spor

24

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


21

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.


1
Aslında, bu sadece sorgu anonim bir tür döndürdüğünde çalışır inanıyorum. Özel bir tür döndürürse, 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 .
Chad Levy

8
Bu teknik System.Data.Objects.ObjectQuery``1[MyProject.Models.Product]benim için üretiyor .
Carl G

1
@CarlG System.Data.Objects.ObjectQuery, EF 4.1 (DbContext) değildir. DbContext kullanarak bu sistem "ToString ()" çağrısında SQL çıktısını veren System.Data.Entity.Infrastructure.DbQuery`1 [MyProject.Models.Product] olacaktır
springy76

Bu, üretilen SQL, nerede, çıkış penceresinde verecektir? açılır menüden hangi seçenek?
JsonStatham

17

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 ( ) OnConfiguringyönteminizi geçersiz kılın ; sorgularınız konsola giriş yapmalıdır:DbContextYourCustomDbContext

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 Startupsınıf ConfigureServicesyöntemi (yerine geçersiz kılma OnConfiguringyöntemi; yarar arasında gevşek bir bağlantı olan DbContextveILoggerProvider kullanmak isteyen)
  • Bir uygulama ILoggerProvider( ConsoleLoggerProvideryukarı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 MyLoggergü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;
        }
    } 
}

Yani ... yeni başlayanlar bunu yapmanın bir yolu yok mu?
Juan De la Cruz

1
@JuanDelaCruz Cevabımı basitleştirdim; basit alternatifi deneyin
The Red Pea

16

İki yol vardır:

  1. Oluşturulacak SQL'i görüntülemek için arayın 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.
  2. Seçtiğiniz SQL sunucunuza, son sorguyu tüm ayrıntılarında gösterecek bir izleyici ekleyebilirsiniz. MySQL durumunda, sorguları izlemenin en kolay yolu sorgu günlüğünü kuyruğa almaktır 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.

27
Neyin ToTrace durumu?
nos

Nick, cevabımı gönderdikten hemen sonra Nick'in belirttiği gibi ObjectQuery.
Benjamin Pollack

2
SQL Server Profiler ilk 4000 karakteri yakalar, ancak EF sorguları bundan daha uzun olabilir.

7

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.


En iyi cevap!
AlexSC

7

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


1
üzgünüm thats sadece SQL sunucusu için değil, MySQL
andrew pate


5
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


4
Ben sadece denedim ve nesne izler: Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable1 [System.Linq.IGrouping 2[System.Int32,String]]yerine gerçek sorgu. Bir şey mi kaçırıyorum yoksa bir şeyden bahsetmeyi unuttun mu?
loganjones16

5

Entegrasyon testi yapıyorum ve Entity Framework Core 2.1 oluşturulan SQL deyimi hata ayıklamak için gerekli, bu yüzden kullanmak DebugLoggerProviderya ConsoleLoggerProviderda 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ı:

Örnek SQL deyimi çıktısı


1
DebugLoggerPrivider ve ConsoleLoggerProvider yalnızca .NET Core'da var gibi görünüyor: docs.microsoft.com/en-us/dotnet/api/…
Gabriel Magana

4

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


    }


}

EF Core 2.0.1 ve yukarıdaki öneri sonuçlarını kullanıyorum: System.InvalidCastException: 'Microsoft.EntityFrameworkCore.Query.Internal.InMemoryQueryModelVisitor' türü '' Microsoft.EntityFrameworkCore.Query.RelationalQueryModelVisitor 'for' yazın ' satır: var modelVisitor = (RelationalQueryModelVisitor) queryCompilationContext.CreateQueryModelVisitor();
Chris Wolf

2
@ChrisWolf Orijinal yazarın özünü takip ederseniz , bu uzantı yönteminin güncellenmiş bir sürümünü sağlayan birini bulabilirsiniz . Benim için çalıştı.
B12Toaster

2

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.


2

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

Evet, ama hiç kimsenin p__linq__i'yi görmek istemediğine inanıyorum, ama gerçek değerler
Tom Stickel

Bu şekilde EF 6'da hala çalışır ve yalnızca sorgu yapısının nasıl göründüğünü önemsiyorsanız faydalı olacaktır. Benim durumumda IQueryable <T> nesnesini oluşturduğum projenin System.Data.Entity'ye referansı yok, ne de sadece hata ayıklama amacıyla eklemek istiyorum. Bu yöntem işe yaradı.
wctiger

2

Benim için, EF6 ve Visual Studio 2015 kullanarak queryhemen pencereye girdim ve bana üretilen SQL İfadesini verdi


1

Parametre değerlerine (yalnızca değerlerine değil @p_linq_0aynı zamanda değerlerine de) sahip olmak istiyorsanız, yönteme IDbCommandInterceptorbazı günlükleri kullanabilir ve ekleyebilirsiniz ReaderExecuted.


1

İ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();

0

Entity Framework 4 Çözümü

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;
    }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.