Làm cách nào để tôi xem SQL được tạo bởi Entity Framework?


624

Làm cách nào để tôi xem SQL được tạo bởi khung thực thể?

(Trong trường hợp cụ thể của tôi, tôi đang sử dụng nhà cung cấp mysql - nếu có vấn đề)


1
Bài báo này từ Tạp chí MSDN mô tả một số tùy chọn định hình cho Entity Framework 4
Arve 8/211

2
Câu hỏi "trùng lặp" được liên kết là dành cho LINQ với SQL, vì vậy nó không thực sự là một bản sao.
jrummell

2
Khi chạy theo trình gỡ lỗi, IntelliTrace hiển thị các truy vấn SQL được thực hiện, mặc dù không có kết quả.
ivan_pozdeev

Nếu bạn muốn thấy SQL ngay khi đang phát triển, bạn có thể sử dụng LINQPad . Khi bạn chạy truy vấn LINQ trong kết quả, sẽ có một tab SQL hiển thị câu lệnh SQL được thực thi. Đối với myQuery, bạn sẽ phải cài đặt trình điều khiển. Tôi không có sẵn cơ sở dữ liệu myQuery, nhưng nó sẽ hoạt động.
gligoran

Câu trả lời:


472

Bạn có thể làm như sau:

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

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

hoặc trong EF6:

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

Điều đó sẽ cung cấp cho bạn SQL đã được tạo.


20
Bạn sẽ không nhận được SQL cho các truy vấn kết thúc bằng .Single (), .Count (), .Any (), v.v. theo cách đó.
springy76

24
Đó là bởi vì sau khi chạy .Single()đối tượng của bạn không còn nữa IQueryabletôi đoán.
Suhas

11
với EF6, tôi chỉ có thể nhận được nó với sự phản chiếu. nhưng trước tiên, tôi đã phải chuyển đổi resultđể System.Data.Entity.Infrastructure.DbQuery<T>, sau đó nhận được tài sản nội bộ InternalQuerynhư (System.Data.Entity.Internal.Linq.InternalQuery<T>), và chỉ khi đó, sử dụngToTraceString()
itsho

9
thêm tham chiếu đến System.Data.Entity, System.Data.Objects.ObjectQuery tồn tại trong dll trên
Mahesh

54
Trong EF6 bạn chỉ có thể làmresult.ToString()
Scott Chamberlain

956

Đối với những người sử dụng Entity Framework 6 trở lên, nếu bạn muốn xem SQL đầu ra trong Visual Studio (như tôi đã làm), bạn phải sử dụng chức năng ghi nhật ký / chặn mới.

Thêm dòng sau sẽ nhổ SQL được tạo ra (cùng với các chi tiết liên quan đến thực thi bổ sung) trong bảng đầu ra Visual Studio:

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

Thông tin thêm về đăng nhập vào EF6 trong loạt blog tiện lợi này: http://blog.oneunicorn.com/2013/05/08/ef6-sql-logging-part-1-simple-logging/

Lưu ý: Đảm bảo bạn đang chạy dự án của mình ở chế độ DEBUG.


107
Câu trả lời này xứng đáng được yêu thích hơn (nếu bạn đang sử dụng EF6 +) - bổ sung gỡ lỗi tuyệt vời, chỉ cần thêm nó vào công cụ xây dựng DBContext (this.Database.Log = ...)
keithl8041 7/214

21
Đảm bảo rằng bạn đang chạy dự án của mình trong DEBUG MODE, kiểm tra xem mục "Gỡ lỗi" đã được chọn trên hộp tổ hợp của ngăn đầu ra chưa và cũng kiểm tra xem gỡ lỗi của bạn không chuyển hướng đến Ngay lập tức (Công cụ> Tùy chọn> Gỡ lỗi> Chuyển hướng tất cả văn bản Cửa sổ đầu ra sang Ngay lập tức Cửa sổ)
rkawano

5
Có cách nào để có được điều này để bao gồm các giá trị biến trực tiếp trong sql được tạo không? Một chút đau đớn với những người lớn hơn.
Chris

22
@Matt Nibecker Điều này không hoạt động trong EF Core. Cái gì thay thế cho EF Core?
nam

9
CẢNH BÁO: Tôi đã thực hiện điều này với ý định nó chỉ chạy trong quá trình phát triển. Khi chúng tôi triển khai vào môi trường thử nghiệm của mình, chúng tôi bắt đầu đột ngột thấy rò rỉ bộ nhớ trong Quy trình công nhân IIS. Sau khi lược tả bộ nhớ, chúng tôi nhận ra ngay cả GC rõ ràng không thu thập các đối tượng bối cảnh thực thể nữa (vâng, chúng đang sử dụng các câu lệnh). Loại bỏ dòng này trở lại tất cả bình thường. Vì vậy, trong khi đây là một công cụ tuyệt vời, hãy đảm bảo bạn chỉ xây dựng nó vào ứng dụng của mình để phát triển.
Brandon Barkley

82

Bắt đầu với EF6.1, bạn có thể sử dụng Thiết bị chặn để đăng ký bộ ghi cơ sở dữ liệu. Xem các chương "Đánh chặn" và "Ghi nhật ký hoạt động cơ sở dữ liệu" vào một tệp tại đây

<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
Bài đăng trên blog về chủ đề blog.oneunicorn.com/2014/02/09/ Ấn
Tim Abell

12
Chính xác, nó nằm dưới: <configure> <entityFramework> <đánh chặn> ... </ đánh chặn> </ entityFramework> </ configure>
Barshe P

80

Nếu bạn đang sử dụng DbContext, bạn có thể thực hiện các thao tác sau để nhận SQL:

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

12
ToString()sẽ cung cấp cho bạn truy vấn với các biến trong nó, như p__linq__0, thay vì các giá trị chính thức (ví dụ: 34.563 thay vì p__linq__0)
thể thao

24

Áp dụng cho EF 6.0 trở lên: Dành cho những bạn muốn biết thêm về chức năng ghi nhật ký và thêm vào một số câu trả lời đã được đưa ra.

Bất kỳ lệnh nào được gửi từ EF đến cơ sở dữ liệu bây giờ có thể được ghi lại. Để xem các truy vấn được tạo từ EF 6.x, hãy sử dụngDBContext.Database.Log property

Những gì được ghi lại

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

Thí dụ:

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

Đầu ra:

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

Để đăng nhập vào một tập tin bên ngoài:

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

Thêm thông tin ở đây: Ghi nhật ký và chặn hoạt động cơ sở dữ liệu


21

Bạn có thể làm như sau trong EF 4.1:

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

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

Điều đó sẽ cung cấp cho bạn SQL đã được tạo.


1
Thực tế, tôi tin rằng điều này chỉ hoạt động khi truy vấn trả về một loại ẩn danh. Nếu nó trả về một loại tùy chỉnh, ToString()đầu ra là không gian tên của loại tùy chỉnh đó. Ví dụ: nếu mã ở trên là select new CustomType { x = x.Name }, giá trị được trả về sẽ giống như Company.Models.CustomTypethay vì SQL được tạo.
Chad Levy

8
Kỹ thuật này tạo ra System.Data.Objects.ObjectQuery``1[MyProject.Models.Product]cho tôi.
Carl G

1
@CarlG System.Data.Objects.ObjectQuery không phải là EF 4.1 (DbContext). Sử dụng DbContext, nó sẽ là System.Data.Entity.Infr Hạ tầng.DbQuery`1 [MyProject.Models. Productt] thực sự tạo ra SQL của nó trong lệnh gọi "ToString ()"
springy76

Điều này sẽ cung cấp cho bạn SQL đã được tạo, ở đâu, trong cửa sổ đầu ra? lựa chọn nào từ danh sách thả xuống?
JsonStatham

17

Câu trả lời của tôi giải quyết lõi EF . Tôi tham khảo vấn đề github này và các tài liệu về cấu hìnhDbContext :

Đơn giản

Ghi đè OnConfiguringphương thức của DbContextlớp của bạn ( YourCustomDbContext) như được hiển thị ở đây để sử dụng ConsoleLoggerProvider; truy vấn của bạn sẽ đăng nhập vào bảng điều khiển:

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
}

Phức tạp

Trường hợp phức tạp này tránh trọng các DbContext OnConfiguringphương pháp. , điều không được khuyến khích trong các tài liệu: "Cách tiếp cận này không cho vay để thử nghiệm, trừ khi các thử nghiệm nhắm vào cơ sở dữ liệu đầy đủ."

Trường hợp phức tạp này sử dụng:

  • Các IServiceCollection trong Startuplớp ConfigureServicesphương pháp (thay vì trọng các OnConfiguringphương pháp; lợi ích là một khớp nối lỏng lẻo giữa DbContextILoggerProviderbạn muốn sử dụng)
  • Thực hiện ILoggerProvider (thay vì sử dụng ConsoleLoggerProvidertriển khai được hiển thị ở trên; lợi ích là việc triển khai của chúng tôi cho thấy cách chúng tôi sẽ đăng nhập vào Tệp (Tôi không thấy Nhà cung cấp ghi nhật ký tệp được vận chuyển với EF Core ))

Như thế này:

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

Đây là việc triển khai MyLoggerProvider(và bổ sung MyLoggernhật ký của nó vào Tệp mà bạn có thể định cấu hình; các truy vấn EF Core của bạn sẽ xuất hiện trong tệp.)

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

Vì vậy, ... không có cách bắt đầu làm việc đó?
Juan De la Cruz

1
@JuanDelaCruz Tôi đã đơn giản hóa câu trả lời của mình; thử phương án đơn giản
Hạt đậu đỏ

16

Có hai cách:

  1. Để xem SQL sẽ được tạo, chỉ cần gọi ToTraceString() . Bạn có thể thêm nó vào cửa sổ đồng hồ của mình và đặt điểm dừng để xem truy vấn sẽ ở điểm nào cho bất kỳ truy vấn LINQ nào.
  2. Bạn có thể đính kèm một bộ theo dõi vào máy chủ SQL mà bạn chọn, nó sẽ hiển thị cho bạn truy vấn cuối cùng trong tất cả các chi tiết chính của nó. Trong trường hợp của MySQL, cách dễ nhất để theo dõi các truy vấn chỉ đơn giản là theo đuôi nhật ký truy vấn tail -f. Bạn có thể tìm hiểu thêm về các cơ sở ghi nhật ký của MySQL trong tài liệu chính thức . Đối với SQL Server, cách dễ nhất là sử dụng trình lược tả SQL Server đi kèm.

27
ToTraceString của cái gì?
số

ObjectQuery, như Nick đã lưu ý ngay sau khi tôi đăng phản hồi của mình.
Benjamin Pollack

2
SQL Server Profiler thu được 4000 ký tự đầu tiên, nhưng các truy vấn EF có thể dài hơn thế.

7

Để có truy vấn luôn tiện dụng, không cần thay đổi mã, hãy thêm mã này vào DbContext của bạn và kiểm tra nó trên cửa sổ đầu ra trong phòng thu trực quan.

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

Tương tự như câu trả lời @Matt Nibecker, nhưng với điều này, bạn không phải thêm nó vào mã hiện tại của mình, mỗi khi bạn cần truy vấn.


Câu trả lời tốt nhất!
AlexSC

7

SQL Management Studio => Công cụ => Trình hồ sơ SQL Server

Tệp => Dấu vết mới ...

Sử dụng Mẫu => Trống

Lựa chọn sự kiện => T-SQL

Kiểm tra Lefthandside cho: SP.StmtComplete

Bộ lọc cột có thể được sử dụng để chọn một ApplicationName hoặc DatabaseName cụ thể

Bắt đầu hồ sơ đó chạy sau đó kích hoạt truy vấn.

Nhấn vào đây để biết thông tin nguồn


1
xin lỗi đó chỉ dành cho máy chủ SQL, không phải MySQL
pate


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

Sẽ trả về truy vấn sql. Làm việc bằng cách sử dụng datacontext của EntityFramework 6


4
Tôi vừa thử cái này và nó tìm ra đối tượng: Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable1 [System.Linq.IGrouping 2[System.Int32,String]]thay vì truy vấn thực tế. Tôi đang thiếu một cái gì đó hoặc bạn đã quên đề cập đến một cái gì đó?
loganjones16

5

Tôi đang thực hiện kiểm tra tích hợp và cần điều này để gỡ lỗi câu lệnh SQL được tạo trong Entity Framework Core 2.1, vì vậy tôi sử dụng DebugLoggerProviderhoặc ConsoleLoggerProvidertương tự như vậy:

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

        ........

Đây là một đầu ra mẫu từ bảng điều khiển Visual Studio:

Đầu ra câu lệnh SQL mẫu


1
DebugLoggerPrivider và ConsoleLoggerProvider dường như chỉ tồn tại trong .NET Core: docs.microsoft.com/en-us/dotnet/api/ trộm
Gabriel Magana

4

Necromance.
Trang này là kết quả tìm kiếm đầu tiên khi tìm kiếm giải pháp cho bất kỳ .NET Framework nào, vì vậy đây là dịch vụ công cộng, cách thức thực hiện trong EntityFramework Core (cho .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);

Và sau đó là các phương thức mở rộng này (IQueryableExtensions1 cho .NET Core 1.0, IQueryableExtensions cho .NET Core 2.0):

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


    }


}

Tôi đang sử dụng EF Core 2.0.1 và kết quả đề xuất ở trên trong: System.InvalidCastException: 'Không thể truyền đối tượng thuộc loại Microsoft.EntityFrameworkCore.Query.Iternal.InMemoryQueryModelVisitor' để gõ '' Microsoft.EntityFramework dòng: var modelVisitor = (RelationalQueryModelVisitor) queryCompilationContext.CreateQueryModelVisitor();
Chris Wolf

2
@ChrisWolf nếu bạn theo ý chính của tác giả ban đầu, bạn có thể tìm thấy ai đó đã cung cấp phiên bản cập nhật của phương thức mở rộng đó . Đã làm cho tôi.
B12Toaster

2

Trong trường hợp của tôi cho EF 6+, thay vì sử dụng điều này trong Cửa sổ ngay lập tức để tìm chuỗi truy vấn:

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

Cuối cùng tôi đã phải sử dụng điều này để nhận lệnh SQL được tạo:

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

Tất nhiên chữ ký loại ẩn danh của bạn có thể khác nhau.

HTH.


2

Tôi vừa mới làm điều này:

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

Và kết quả hiển thị trong Kết quả :

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

Có, nhưng tôi tin rằng Không ai muốn xem p__linq__i, nhưng giá trị thực
Tom Stickel

Cách này vẫn hoạt động trong EF 6 và sẽ hữu ích nếu bạn chỉ quan tâm đến cấu trúc truy vấn trông như thế nào. Trong trường hợp của tôi, dự án tôi tạo đối tượng <T> IQueryable không có tham chiếu đến System.Data.Entity và tôi không muốn thêm nó chỉ nhằm mục đích gỡ lỗi. Vì vậy, phương pháp này làm việc tốt.
wctiger

2

Đối với tôi, sử dụng EF6 và Visual Studio 2015 tôi đã nhập vào querycửa sổ ngay lập tức và nó đã cho tôi Báo cáo SQL được tạo


1

Nếu bạn muốn có các giá trị tham số (không chỉ @p_linq_0mà cả giá trị của chúng), bạn có thể sử dụng IDbCommandInterceptorvà thêm một số ghi nhật ký vào ReaderExecutedphương thức.


1

Trong khi có câu trả lời tốt ở đây, không ai giải quyết vấn đề của tôi hoàn toàn (Tôi muốn có được toàn bộ câu lệnh SQL, bao gồm cả thông số , từ DbContext từ bất kỳ IQueryable. Các mã sau đây làm việc đó. Đó là một sự kết hợp của các đoạn mã từ Google. Tôi đã chỉ thử nghiệm nó với EF6 + .

Chỉ là một bên, nhiệm vụ này đã đưa tôi đi lâu hơn tôi nghĩ nó sẽ. Trừu tượng hóa trong Entity Framework là một chút, IMHO.

Đầu tiên là sử dụng. Bạn sẽ cần một tham chiếu rõ ràng đến '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;

Lớp sau đây chuyển đổi một IQueryable thành DataTable. Sửa đổi theo nhu cầu của bạn có thể là:

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

Để sử dụng, chỉ cần gọi nó như dưới đây:

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

0

Giải pháp khung thực thể 4

Hầu hết các câu trả lời ở đây là dành riêng cho EF6. Đây là một trong những bạn vẫn đang sử dụng EF4.

Phương pháp này thay thế @p__linq__0/ etc. tham số với các giá trị thực của chúng, vì vậy bạn chỉ cần sao chép và dán đầu ra vào SSMS và chạy hoặc gỡ lỗi nó.

    /// <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;
    }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.