the bug hunting!
Hoy me han remitido un caso muy curioso de EF y el tratamiento de los campos DateTime. Básicamente, lo que me comentaban era que EF generaba una consulta incorrecta incluyendo un CAST a DateTime2, con lo cual hacía imposible la utilización del índice que la base de datos tenía sobre esta columna. Para seros sinceros, me sonó raro, puesto que es habitual ver el profiling de las consultas y me hubiera cantado a la primera, por lo que me puse a investigar el tema. Como siempre, lo primero es una aplicación de mínimos y por ello, nada más tonto que lo siguiente:
1 |
<span style="color: #0000ff">public</span> <span style="color: #0000ff">class</span> UnitOfWork |
1 |
:DbContext |
1 |
  |
1 |
<span style="color: #0000ff">public</span> IDbSet<Sample> Samples { get; set; } |
1 |
  |
1 |
ublic <span style="color: #0000ff">class</span> Sample |
1 |
  |
1 |
<span style="color: #0000ff">public</span> <span style="color: #0000ff">int</span> Id { get; set; } |
1 |
<span style="color: #0000ff">public</span> DateTime Fecha { get; set; } |
Ahora, solamente nos queda tirar una consulta y ver que se está ejecutando:
1 |
<span style="color: #0000ff">static</span> <span style="color: #0000ff">void</span> QueryWithoutCastToDateTime2() |
1 |
{ |
1 |
<span style="color: #0000ff">using</span> (UnitOfWork uow = <span style="color: #0000ff">new</span> UnitOfWork()) |
1 |
{ |
1 |
DateTime fechaInit = DateTime.Now.AddDays(-2); |
1 |
DateTime fechaFin = DateTime.Now; |
1 |
var result = uow.Samples.Where(d => fechaInit < d.Fecha && d.Fecha < fechaFin).ToList(); |
1 |
} |
1 |
} |
1 |
exec sp_executesql N<span style="color: #006080">'SELECT |
1 |
[Extent1].[Id] AS [Id], |
1 |
[Extent1].[Fecha] AS [Fecha] |
1 |
FROM [dbo].[Samples] AS [Extent1] |
1 |
<p>WHERE (@p__linq__0 < [Extent1].[Fecha]) AND ([Extent1].[Fecha] < @p__linq__1)'</span>,N<span style="color: #006080">'@p__linq__0 datetime2(7),@p__linq__1 datetime2(7)'</span>,@p__linq__0=<span style="color: #006080">'2012-03-25 18:16:30.5246971'</span>,</p><p>@p__linq__1=<span style="color: #006080">'2012-03-27 18:16:30.5251972'</span></p> |
Bien, perfecto.. No veo el problema que se comenta!!!!!!!!! Revisando el código en el que aparecía este problema, buscando cualquier nota diferente como que estuviera forzando el tipo a DateTime2 etc.. nos dimos cuenta que la única diferencia era que en su ejemplo los campos eran Nullables. Por lo tanto, probamos a cambiar el ejemplo tonto anterior haciendo uso de DateTime?.
1 |
<span style="color: #0000ff">static</span> <span style="color: #0000ff">void</span> QueryWithCastToDateTime2() |
1 |
{ |
1 |
<span style="color: #0000ff">using</span> (UnitOfWork uow = <span style="color: #0000ff">new</span> UnitOfWork()) |
1 |
{ |
1 |
DateTime? fechaInit = DateTime.Now.AddDays(-2); |
1 |
DateTime? fechaFin = DateTime.Now; |
1 |
var result = uow.Samples.Where(d => fechaInit < d.Fecha && d.Fecha < fechaFin).ToList(); |
1 |
} |
1 |
} |
Revisando la consulta con el profiler nos dimos cuenta de que efectivamente, si hacemos uso de DateTime? las consultas generan un CAST incorrecto que tira por tierra nuestros índices…
1 |
exec sp_executesql N<span style="color: #006080">'SELECT |
1 |
[Extent1].[Id] AS [Id], |
1 |
[Extent1].[Fecha] AS [Fecha] |
1 |
FROM [dbo].[Samples] AS [Extent1] |
1 |
WHERE |
1 |
(@p__linq__0 < CAST( [Extent1].[Fecha] AS datetime2)) |
1 |
AND |
1 |
( CAST( [Extent1].[Fecha] AS datetime2) < @p__linq__1)'</span> |
1 |
,N<span style="color: #006080">'@p__linq__0 datetime2(7),@p__linq__1 datetime2(7)'</span>, |
1 |
@p__linq__0=<span style="color: #006080">'2012-03-25 18:17:38.1257814'</span>, |
1 |
@p__linq__1=<span style="color: #006080">'2012-03-27 18:17:38.1262814'</span> |
Por supuesto esto es un bug, un bug que esperemos que arreglen en la siguiente versión, mientras tanto, ya sabéis, cuidado con los DateTime?.
P.d: Vizoso, gracias por reportar el bug!!
Saludos
Unai