Entity Framework에서 생성 한 SQL을 어떻게 봅니까?


624

엔터티 프레임 워크에서 생성 된 SQL을 어떻게 봅니까?

(필자의 경우 mysql 공급자를 사용하고 있습니다-중요하다면)


1
MSDN Magazine 의이 기사는 Entity Framework 4
Arve

2
연결된 "중복"질문은 LINQ to SQL에 대한 것이므로 실제로는 중복되지 않습니다.
jrummell

2
디버거에서 실행될 때 IntelliTrace는 결과가 없어도 SQL 쿼리를 표시합니다.
ivan_pozdeev

개발하는 동안 SQL을 보는 데 관심이 있다면 LINQPad 를 사용할 수 있습니다 . 결과에서 LINQ 쿼리를 실행하면 실행 된 SQL 문을 보여주는 SQL 탭이 나타납니다. mySQL의 경우 드라이버를 설치해야합니다. 사용 가능한 mySQL 데이터베이스가 없지만 작동해야합니다.
gligoran

답변:


472

다음을 수행 할 수 있습니다.

IQueryable query = from x in appEntities
             where x.id == 32
             select x;

var sql = ((System.Data.Objects.ObjectQuery)query).ToTraceString();

또는 EF6에서 :

var sql = ((System.Data.Entity.Core.Objects.ObjectQuery)query)
            .ToTraceString();

그러면 생성 된 SQL이 제공됩니다.


20
그런 식으로 .Single (), .Count (), .Any () 등으로 끝나는 쿼리에 대해서는 SQL을 얻지 못합니다.
springy76

24
그것은 .Single()객체를 실행 한 후에 더 이상 IQueryable추측 하지 않기 때문 입니다.
Suhas

11
EF6을 사용하면 반사로 만 얻을 수 있습니다. 그러나 첫째, 나는 변환했다 result위해 System.Data.Entity.Infrastructure.DbQuery<T>, 다음 내부 속성 수 InternalQuery등을 (System.Data.Entity.Internal.Linq.InternalQuery<T>), 오직 다음, 사용ToTraceString()
itsho

9
System.Data.Entity에 대한 참조 추가, System.Data.Objects.ObjectQuery는 위의 dll에 존재
Mahesh

54
EF6에서 당신은 할 수result.ToString()
스콧의 전관

955

Entity Framework 6 이상을 사용하는 사용자의 경우 Visual Studio에서 출력 SQL을 보려면 (내처럼) 새로운 로깅 / 차단 기능을 사용해야합니다.

다음 행을 추가하면 Visual Studio 출력 패널에서 생성 된 SQL (추가 실행 관련 세부 사항과 함께)이 분리됩니다.

using (MyDatabaseEntities context = new MyDatabaseEntities())
{
    context.Database.Log = s => System.Diagnostics.Debug.WriteLine(s);
    // query the database using EF here.
}

이 멋진 블로그 시리즈에서 EF6에 로그인하는 방법에 대한 자세한 정보 : http://blog.oneunicorn.com/2013/05/08/ef6-sql-logging-part-1-simple-logging/

참고 : 프로젝트를 디버그 모드로 실행 중인지 확인하십시오.


107
이 답변은 더 많은 사랑을받을 가치가 있습니다 (EF6 +를 사용하는 경우)-훌륭한 디버그 추가, DBContext 생성자에 추가하십시오 (this.Database.Log = ...)
keithl8041

21
디버그 모드에서 프로젝트를 실행 중인지 확인하고 출력 창의 콤보 박스에서 "디버그"항목이 선택되어 있는지 확인하고 디버그가 즉시로 리디렉션되지 않는지 확인하십시오 (도구> 옵션> 디버깅> 모든 출력 창 텍스트를 즉시 리디렉션) 창)
rkawano

5
생성 된 SQL 내에 변수 값을 직접 포함시키는 방법이 있습니까? 더 큰 것들과의 고통.
Chris

22
@Matt Nibecker EF Core에서는 작동하지 않습니다. EF Core의 대안은 무엇입니까?
nam

9
경고 : 개발 중에 만 실행하려는 의도로 이것을 구현했습니다. 테스트 환경에 배포 할 때 IIS 작업자 프로세스에서 메모리 누수가 갑자기 발생하기 시작했습니다. 메모리 프로파일 링 후, 명시 적 GC가 더 이상 엔티티 컨텍스트 객체를 수집하지 않는다는 것을 깨달았습니다 (예, 명령문을 사용 중임). 이 줄을 제거하면 모두 정상으로 돌아 왔습니다. 따라서이 도구는 훌륭한 도구이지만 개발 용 앱에만 빌드해야합니다.
Brandon Barkley 17

82

EF6.1부터 인터셉터를 사용하여 데이터베이스 로거를 등록 할 수 있습니다. 파일에 대한 "인터셉터"및 "데이터베이스 조작 로그"장을 참조 하십시오.

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


12
정밀, 그것은 아래에 있습니다 : <configuration> <entityFramework> <interceptors> ... </ interceptors> </ entityFramework> </ configuration>
Christophe P

80

DbContext를 사용하는 경우 다음을 수행하여 SQL을 얻을 수 있습니다.

var result = from i in myContext.appEntities
             select new Model
             {
                 field = i.stuff,
             };
var sql = result.ToString();

12
ToString()p__linq__0최종 값 대신에 와 같이 변수가 포함 된 쿼리를 제공 합니다 (예 : 대신 34563 p__linq__0)
sports

24

EF 6.0 이상에 해당 : 로깅 기능에 대해 더 알고 싶어하고 이미 제공된 답변 중 일부를 추가하려는 경우.

EF에서 데이터베이스로 전송 된 모든 명령을 기록 할 수 있습니다. EF 6.x에서 생성 된 쿼리를 보려면DBContext.Database.Log property

무엇이 기록 되는가

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

예:

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

산출:

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

외부 파일에 로그하려면

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

자세한 정보는 여기 : 데이터베이스 작업 로깅 및 인터셉트


21

EF 4.1에서 다음을 수행 할 수 있습니다.

var result = from x in appEntities
             where x.id = 32
             select x;

System.Diagnostics.Trace.WriteLine(result .ToString());

그러면 생성 된 SQL이 제공됩니다.


1
사실, 이것은 쿼리가 익명 유형을 반환 할 때만 작동한다고 생각합니다. 사용자 정의 유형을 리턴하면 ToString()출력은 해당 사용자 정의 유형의 네임 스페이스입니다. 예를 들어, 위 코드가 인 경우 생성 된 SQL 대신 select new CustomType { x = x.Name }반환 된 값이 Company.Models.CustomType됩니다.
채드 레비

8
이 기술은 System.Data.Objects.ObjectQuery``1[MyProject.Models.Product]나를 위해 생산 합니다.
Carl G

1
@CarlG System.Data.Objects.ObjectQuery는 EF 4.1 (DbContext)이 아닙니다. DbContext를 사용하여이 될 것 System.Data.Entity.Infrastructure.DbQuery`1 [MyProject.Models.Product] 참으로 "ToString ()"에 대한 호출에의 SQL을 출력한다
springy76

그러면 출력 창에서 생성 된 SQL이 제공됩니까? 드롭 다운에서 어떤 옵션을 사용합니까?
JsonStatham

17

내 대답은 EF 핵심을 해결합니다 . 이 github 문제구성에DbContext 대한 문서를 참조하십시오 .

단순한

ConsoleLoggerProvider를 사용하려면 여기표시된대로 클래스 ( ) 의 OnConfiguring메소드를 대체하십시오 . 쿼리는 콘솔에 기록해야합니다.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
}

복잡한

이 복잡한 경우는 오버라이드 (override) 방지 방법.DbContext OnConfiguring문서에서 권장하지 않습니다. "이 방법은 테스트가 전체 데이터베이스를 대상으로하지 않는 한 테스트 자체에는 적합하지 않습니다."

이 복잡한 경우는 다음을 사용합니다.

  • IServiceCollection에서 Startup클래스 ConfigureServices방법 (대신 재정의 OnConfiguring방법을 상기 이득 간의 느슨한 커플 링이다 DbContext하고는ILoggerProvider 당신이 사용하고자하는)
  • 구현은 ILoggerProvider( ConsoleLoggerProvider위에 표시된 구현 을 사용하는 대신 이점은 구현에 파일에 로그하는 방법을 보여줍니다 ( EF Core와 함께 제공된 파일 로깅 공급자 가 표시되지 않음 )

이처럼 :

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

다음은 MyLoggerProvider(및 MyLogger구성 할 수있는 파일에 로그를 추가하는 EF Core 쿼리가 파일에 표시되는) 구현입니다.

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

그러니 .. 초보자는 방법이 없나요?
Juan De la Cruz

1
@ JuanDelaCruz 나는 대답을 단순화했다. 간단한 대안을 시도하십시오
The Red Pea

16

두 가지 방법이 있습니다.

  1. 생성 될 SQL을 보려면을 호출하면 ToTraceString()됩니다. 감시 창에 추가하고 중단 점을 설정하여 LINQ 쿼리에 대해 특정 시점에 쿼리가 무엇인지 확인할 수 있습니다.
  2. 선택한 SQL Server에 추적 프로그램을 연결하면 모든 쿼리 세부 사항에 대한 최종 쿼리가 표시됩니다. MySQL의 경우 쿼리를 추적하는 가장 쉬운 방법은 간단히 쿼리 로그를로 추적하는 것입니다 tail -f. 공식 문서 에서 MySQL의 로깅 기능에 대해 자세히 알아볼 수 있습니다 . SQL Server의 경우 가장 쉬운 방법은 포함 된 SQL Server 프로파일 러를 사용하는 것입니다.

27
무엇의 ToTraceString?
nos

Nick이 응답을 게시 한 직후 지적한 ObjectQuery.
Benjamin Pollack

2
SQL Server 프로파일 러는 처음 4000자를 캡처하지만 EF 쿼리는 그보다 훨씬 길 수 있습니다.

7

쿼리를 항상 편리하게하려면 코드를 변경하지 않고이를 DbContext에 추가하고 Visual Studio의 출력 창에서 확인하십시오.

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        Database.Log = (query)=> Debug.Write(query);
    }

@Matt Nibecker 답변과 비슷하지만 쿼리가 필요할 때마다 현재 코드에 추가 할 필요가 없습니다.


가장 좋은 답변!
AlexSC

7

SQL Management Studio => 도구 => SQL Server 프로파일 러

파일 => 새 추적 ...

템플릿 사용 => 비우기

이벤트 선택 => T-SQL

왼쪽 확인 : SP.StmtComplete

열 필터를 사용하여 특정 ApplicationName 또는 DatabaseName을 선택할 수 있습니다.

해당 프로필을 실행 한 다음 쿼리를 트리거하십시오.

소스 정보를 보려면 여기를 클릭하십시오


1
죄송합니다. MySQL이 아니라 SQL 서버에 대해서만
andrew pate


5
IQueryable query = from x in appEntities
                   where x.id = 32
                   select x;
var queryString = query.ToString();

SQL 쿼리를 반환합니다. EntityFramework 6의 데이터 컨텍스트를 사용하여 작업


4
방금 이것을 시도 하고 실제 쿼리 대신 Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable1 [System.Linq.IGrouping 개체를 추적 2[System.Int32,String]]합니다. 내가 뭔가를 놓치고 있거나 언급하는 것을 잊었습니까?
loganjones16

5

나는 통합 테스트를하고,이 필요 내가 사용하므로, 엔티티 프레임 워크 코어 2.1에서 생성 된 SQL 문을 디버깅하고 DebugLoggerProvider또는 ConsoleLoggerProvider이렇게 같은 :

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

        ........

다음은 Visual Studio 콘솔의 샘플 출력입니다.

샘플 SQL 문 출력


1
DebugLoggerPrivider와 ConsoleLoggerProvider는 .NET Core에만 존재하는 것 같습니다 : docs.microsoft.com/en-us/dotnet/api/…
Gabriel Magana

4

괴롭힘.
이 페이지는 모든 .NET Framework에 대한 솔루션을 검색 할 때의 첫 번째 검색 결과이므로, 여기에서는 공용 서비스로서 EntityFramework Core (.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);

그런 다음 이러한 확장 방법 (.NET Core 1.0 용 IQueryableExtensions1, .NET Core 2.0 용 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을 사용하고 있으며 위의 제안 결과는 다음과 같습니다. 라인 : var modelVisitor = (RelationalQueryModelVisitor) queryCompilationContext.CreateQueryModelVisitor();
크리스 울프

2
@ChrisWolf 원저자의 요지를 따르는 경우 해당 확장 방법의 업데이트 된 버전제공 한 사람을 찾을 수 있습니다 . 나를 위해 일했다.
B12Toaster

2

필자의 경우 EF 6+의 경우 직접 실행 창에서 이것을 사용하여 쿼리 문자열을 찾는 대신 :

var sql = ((System.Data.Entity.Core.Objects.ObjectQuery)query).ToTraceString();

생성 된 SQL 명령을 얻기 위해 이것을 사용해야했습니다.

var sql = ((System.Data.Entity.Infrastructure.DbQuery<<>f__AnonymousType3<string,string,string,short,string>>)query).ToString();

물론 익명 형식의 서명이 다를 수 있습니다.

HTH.


2

방금이 작업을 수행했습니다.

IQueryable<Product> query = EntitySet.Where(p => p.Id == id);
Debug.WriteLine(query);

그리고 결과는 출력에 표시됩니다 .

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

네,하지만 아무도 p__linq__i를보고 싶지는 않지만 실제 값을보고 싶습니다
Tom Stickel

이 방법은 여전히 ​​EF 6에서 작동하며 쿼리 구조의 모양 만 신경 쓰면 도움이됩니다. 필자의 경우 IQueryable <T> 개체를 만드는 프로젝트에 System.Data.Entity에 대한 참조가 없거나 디버깅 목적으로 만 추가하고 싶습니다. 따라서이 방법은 잘 작동했습니다.
wctiger

2

나에게 EF6과 Visual Studio 2015 query를 사용하여 즉시 창에 입력 하여 생성 된 SQL 문을 제공했습니다.



1

좋은 해답이 여기가 있지만, 아무도 완전히 내 문제는 (I 전체 SQL 문을 얻을 싶다고 해결되지 매개 변수를 포함하여 어떤 된 IQueryable에서 DbContext에서. 다음 코드는 구글에서 코드 조각의 조합이 단지. 않습니다. I를 EF6 +에서만 테스트했습니다 .

제쳐두고,이 작업은 생각보다 오래 걸렸습니다. Entity Framework의 추상화는 약간 중요합니다. IMHO.

먼저 사용합니다. '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;

다음 클래스는 IQueryable을 DataTable로 변환합니다. 필요에 따라 수정하십시오.

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

사용하려면 다음과 같이 간단히 전화하십시오.

var context = new MyContext();
var data = ....//Query, return type can be anonymous
    .AsQueryable();
var dt = new EntityFrameworkCommand()
    .Initialize(context, data)
    .GetData();

0

엔터티 프레임 워크 4 솔루션

여기에있는 대부분의 답변은 EF6 전용입니다. 아직 EF4를 사용하는 사람들을위한 것입니다.

이 방법은 @p__linq__0/ etc를 대체합니다 . 실제 값이 포함 된 매개 변수를 사용하면 SSMS에 출력을 복사하여 붙여 넣어 실행하거나 디버깅 할 수 있습니다.

    /// <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;
    }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.