在EF 4.1 DbContext中如何跟踪生成的SQL

时间:2011-04-09 05:51:15

标签: sql logging entity-framework-4 entity-framework-4.1 tracing

我想知道如何在LinqToSql中跟踪生成的SQL,如DataContext。

我还在Jaroslaw Kowalski的博客上阅读了有关EFProviderWrapper解决方案的文章,但它基于ObjectContext,不适用于DbContext。

任何人都知道如何在DbContext中执行此操作?

谢谢。

8 个答案:

答案 0 :(得分:16)

使用DbContextDbSet<T>的最简单方法就是在您构建的ToString()上使用IQueryable。例如:

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

string sql = query.ToString();

sql包含SQL命令,该命令将在执行查询时发布给数据库。

答案 1 :(得分:1)

MVC-Mini-Profiler是一个功能强大的工具,不仅可以跟踪生成的sql,还可以分析工具。

Using mvc-mini-profiler database profiling with Entity Framework Code First

答案 2 :(得分:0)

我使用SQL Server探查器工具来确切地查看已创建的SQL。还有http://efprof.com/,但价格相当高。

答案 3 :(得分:0)

您可以使用ObjectQuery.ToTraceString方法查看存储命令(例如SQL语句)。 MSDN上的How To将向您展示如何使用它。

请注意,在许多情况下,您可以将IQueryable(Linq扩展方法的返回类型,例如IQueryable.Where)转换为ObjectQuery,以便您可以访问ToTraceString方法。

答案 4 :(得分:0)

我在这里找到了ObjectContext的EFTracingProvider扩展:

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跟踪到即时窗口。

答案 5 :(得分:0)

对于任何不想引入第三方库的人,只是在寻找包含参数的SQL(并且不会被所有反射所扰乱),这个扩展方法从中获取InternalQuery对象和ObjectQuery对象。 DbQuery并在将Parameters返回到字符串后返回ToTraceString。如果失败,则从IQueryable返回无参数ToString:

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

答案 6 :(得分:0)

执行代码,然后运行此查询以查看最后执行的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

答案 7 :(得分:0)

这比使用值替换参数的解决方案(通过@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();
        }
    }