Подтвердить что ты не робот

В EF 4.1 DbContext, как отслеживать сгенерированный SQL

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

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

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

Спасибо.

4b9b3361

Ответ 2

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

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

string sql = query.ToString();

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

Ответ 3

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

Ответ 4

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

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

Ответ 5

Я нашел это расширение 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-запросы в ближайшее окно.

Ответ 6

Для тех, кто не хочет втягивать стороннюю библиотеку и просто ищет 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();
        }
    }

Ответ 7

Выполните свой код, а затем запустите этот запрос, чтобы увидеть последний выполненный 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

Ответ 8

Это небольшое улучшение по сравнению с решением (по @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();
        }
    }