your programing

Entity Framework에서 생성 된 SQL을 보려면 어떻게합니까?

lovepro 2020. 10. 3. 11:23
반응형

Entity Framework에서 생성 된 SQL을 보려면 어떻게합니까?


엔티티 프레임 워크에서 생성 된 SQL을 어떻게 볼 수 있습니까?

(내 특별한 경우에는 mysql 공급자를 사용하고 있습니다-중요한 경우)


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

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이 제공됩니다.


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

다음 줄을 추가하면 생성 된 SQL (추가 실행 관련 세부 정보와 함께)이 Visual Studio 출력 패널에 표시됩니다.

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/

참고 : 프로젝트를 DEBUG 모드에서 실행하고 있는지 확인하십시오.


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

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

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>

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

자세한 정보 : 데이터베이스 작업 로깅 및 차단


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

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

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

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


두 가지 방법이 있습니다.

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

내 대답은 EF core를 다룹니다 . 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
}

복잡한

이 복잡한 경우는 메서드 재정의를 방지 합니다 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));
        ...
    }
}

다음은 a의 구현입니다 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;
        }
    } 
}

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

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

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


글쎄, 나는 현재 그 목적으로 Express 프로파일 러를 사용하고 있지만 단점은 MS SQL Server에서만 작동한다는 것입니다. 이 도구는 https://expressprofiler.codeplex.com/ 에서 찾을 수 있습니다.


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

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


통합 테스트를 수행 중이며 Entity Framework Core 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 문 출력


네크 로맨싱.
이 페이지는 모든 .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
{

    // https://stackoverflow.com/questions/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;
        }


    }


}

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

파일 => 새 추적 ...

템플릿 사용 => 공백

이벤트 선택 => T-SQL

왼쪽 확인 : SP.StmtComplete

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

해당 프로필 실행을 시작한 다음 쿼리를 트리거합니다.

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


필자의 경우 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.


나는 이것을했다 :

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

나를 위해 EF6 및 Visual Studio 2015 query를 사용하여 직접 창에 입력 하고 생성 된 SQL 문을 제공했습니다.


매개 변수 값 (값 @p_linq_0뿐만 아니라 그 값도)도 갖고 싶다면 , 메소드에 IDbCommandInterceptor로깅을 사용 하고 추가 할 수 있습니다 ReaderExecuted.

참고 URL : https://stackoverflow.com/questions/1412863/how-do-i-view-the-sql-generated-by-the-entity-framework

반응형