sql - non - execute query entity
En EF 4.1 DbContext, cómo rastrear SQL generado (8)
Ejecute su código y luego ejecute esta consulta para ver el último SQL ejecutado.
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
Me pregunto cómo rastrear SQL generado como DataContext en LinqToSql.
También leo artículos sobre la solución de EFProviderWrapper en el blog de Jaroslaw Kowalski, pero está basado en ObjectContext, no funciona para DbContext.
¿Alguien sabe cómo hacer esto en DbContext?
Gracias.
El MVC-Mini-Profiler es una herramienta útil, no solo una traza de SQL generada, sino también una herramienta de creación de perfiles.
Uso de perfiles de bases de datos mvc-mini-profiler con el código de Entity Framework primero
Encontré esta extensión EFTracingProvider para ObjectContext aquí:
http://efwrappers.codeplex.com/
Pero el ejemplo es para ObjectContext no DbContext, para que funcione con DbContext haga lo siguiente en el constructor:
Public Sub New()
MyBase.New(EFTracingProviderUtils.CreateTracedEntityConnection("MyDbConnection"), True)
Dim context As ObjectContext = CType(Me, IObjectContextAdapter).ObjectContext
context.EnableTracing()
End Sub
Ah, y recuerda establecer la configuración:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.diagnostics>
<sources>
<source name="EntityFramework.MyDbConnection" switchValue="All" />
</sources>
</system.diagnostics>
Que luego rastrea todo el SQL a la ventana inmediata.
Esta es una ligera mejora con respecto a la solución (por @kmk) que reemplaza los parámetros con valores. Esta solución declara y asigna los parámetros en su lugar:
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();
}
}
Para cualquier persona que no desee obtener en una biblioteca de terceros, y simplemente está buscando el SQL que contiene los parámetros (y no está molesto por todo el reflejo), este método de extensión toma el objeto InternalQuery y el objeto ObjectQuery del DbQuery y regresa ToTraceString luego de realizar nuevamente los Parámetros en la cadena. Si falla, devuelve ToString sin parámetros de 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();
}
}
Puede usar el método ObjectQuery.ToTraceString para ver los comandos de la tienda (por ejemplo, sentencias de SQL). El Cómo en MSDN le mostrará cómo se puede usar.
Tenga en cuenta que, en muchos casos, podrá convertir un IQueryable (el tipo de devolución de los métodos de extensión de Linq como IQueryable.Where ) en un ObjectQuery para que tenga acceso al método ToTraceString.
Utilizo la herramienta de perfil SQL Server para ver exactamente qué SQL se ha creado. También hay http://efprof.com/ pero tiene un precio bastante alto.
La forma más fácil con DbContext
y DbSet<T>
es utilizar ToString()
en IQueryable
que ha creado. Por ejemplo:
var query = context.Blogs.Include(b => b.Posts)
.Where(b => b.Title == "AnyTitle");
string sql = query.ToString();
sql
contiene el comando SQL que se emitirá al DB cuando se ejecuta la consulta.