В EF 4.1 DbContext как отследить сгенерированный SQL - PullRequest
32 голосов
/ 09 апреля 2011

Интересно, как отследить сгенерированный SQL, такой как DataContext, в LinqToSql.

Я также читал статьи о решении EFProviderWrapper в блоге Ярослава Ковальского, но он основан на ObjectContext, не работает для DbContext.

Кто-нибудь знает, как это сделать в DbContext?

Спасибо.

Ответы [ 8 ]

16 голосов
/ 19 июля 2011

Самый простой способ с DbContext и DbSet<T> - это просто использовать ToString() на IQueryable, который вы построили.Например:

var query = context.Blogs.Include(b => b.Posts)
                   .Where(b => b.Title == "AnyTitle");

string sql = query.ToString();

sql содержит команду SQL, которая будет выдана в БД при выполнении запроса.

1 голос
/ 19 июля 2011

MVC-Mini-Profiler - это замечательный инструмент, не только для трассировки, созданной SQL, но и для профилирования.

Использование профилирования базы данных mvc-mini-profiler с Entity Framework Code First

0 голосов
/ 17 июня 2014

Это небольшое улучшение по сравнению с решением (на @kmk), которое заменяет параметры значениями.Это решение объявляет и назначает параметры вместо:

    public static string ToSqlString<TEntity>(this IQueryable<TEntity> queryable) where TEntity : class
    {
        StringBuilder parametersBuilder = new StringBuilder();

        try
        {
            var dbQuery = queryable as DbQuery<TEntity>;

            // 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 oq = oqProp.GetValue(iq, null);

            var objectQuery = oq as ObjectQuery<TEntity>;

            var sqlString = objectQuery.ToTraceString();

            foreach (var objectParam in objectQuery.Parameters)
            {
                SqlMetaData metadata = SqlMetaData.InferFromValue(objectParam.Value, objectParam.Name);
                string sqlType = metadata.TypeName + (metadata.SqlDbType == SqlDbType.NVarChar ? "(" + metadata.MaxLength + ")" : String.Empty);

                parametersBuilder.AppendFormat("declare @{0} {1} = '{2}'", objectParam.Name, sqlType, objectParam.Value);
                parametersBuilder.AppendLine();
            }

            parametersBuilder.AppendLine();
            return parametersBuilder.ToString() + sqlString;
        }
        catch (Exception)
        {
            //squash it and just return ToString
            return queryable.ToString();
        }
    }
0 голосов
/ 09 апреля 2013

Выполните ваш код, а затем выполните этот запрос, чтобы увидеть последний выполненный SQL.

SELECT deqs.last_execution_time AS [Time], dest.TEXT AS [Query]
FROM sys.dm_exec_query_stats AS deqs
CROSS APPLY sys.dm_exec_sql_text(deqs.sql_handle) AS dest
ORDER BY deqs.last_execution_time DESC
0 голосов
/ 02 апреля 2013

Для тех, кто не хочет загружать стороннюю библиотеку и просто ищет SQL, содержащий параметры (и не огорчает все отражение), этот метод расширения извлекает объект InternalQuery и объект ObjectQuery изDbQuery и возвращает ToTraceString после реализации параметров обратно в строку.В случае неудачи он возвращает ToString без параметров из IQueryable:

    public static string ToSqlString<TEntity>(this IQueryable<TEntity> queryable) where TEntity : class
    {
        try
        {
            var dbQuery = queryable as DbQuery<TEntity>;

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

            // get the ObjectQuery internal variable from the IInternalQuery object
            var oqProp = iq.GetType().GetProperty("ObjectQuery", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);

            var oq = oqProp.GetValue(iq);

            var objectQuery = oq as ObjectQuery<TEntity>;

            var sqlString = objectQuery.ToTraceString();

            foreach (var objectParam in objectQuery.Parameters)
            {
                if (objectParam.ParameterType == typeof(string) || objectParam.ParameterType == typeof(DateTime) || objectParam.ParameterType == typeof(DateTime?))
                {
                    sqlString = sqlString.Replace(string.Format("@{0}", objectParam.Name), string.Format("'{0}'", objectParam.Value.ToString()));
                }
                else if (objectParam.ParameterType == typeof(bool) || objectParam.ParameterType == typeof(bool?))
                {
                    bool val;
                    if (Boolean.TryParse(objectParam.Value.ToString(), out val))
                    {
                        sqlString = sqlString.Replace(string.Format("@{0}", objectParam.Name), string.Format("{0}", val ? 1 : 0));
                    }

                }
                else
                {
                    sqlString = sqlString.Replace(string.Format("@{0}", objectParam.Name), string.Format("{0}", objectParam.Value.ToString()));
                }
            }

            return sqlString;
        }
        catch (Exception)
        {
            //squash it and just return ToString
            return queryable.ToString();
        }
    }
0 голосов
/ 04 октября 2011

Я нашел это расширение EFTracingProvider для ObjectContext здесь:

http://efwrappers.codeplex.com/

Но пример для ObjectContext, а не DbContext, чтобы заставить его работать с DbContext выполните следующие действия в конструкторе:

Public Sub New()
  MyBase.New(EFTracingProviderUtils.CreateTracedEntityConnection("MyDbConnection"), True)
  Dim context As ObjectContext = CType(Me, IObjectContextAdapter).ObjectContext
  context.EnableTracing()
End Sub

Да, и не забудьте установить конфигурацию:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.diagnostics>
    <sources>
      <source name="EntityFramework.MyDbConnection" switchValue="All" />
    </sources>
 </system.diagnostics>

Затем выполняется трассировка всего SQL до непосредственного окна.

0 голосов
/ 19 июля 2011

Вы можете использовать метод ObjectQuery.ToTraceString для просмотра команд хранилища (например, операторов SQL). How To в MSDN покажет вам, как его можно использовать.

Обратите внимание, что во многих случаях вы сможете приводить IQueryable (тип возврата из методов расширения Linq, например IQueryable.Where ) для ObjectQuery, чтобы иметь доступ к методу ToTraceString.

0 голосов
/ 09 апреля 2011

Я использую средство профилирования SQL Server, чтобы увидеть, какой именно SQL был создан. Существует также http://efprof.com/, но цена довольно высокая.

...