entity framework - net - DbSet.Find método ridículamente lento en comparación con.SingleOrDefault en ID
mvc entity framework español (1)
Tengo el siguiente código (la base de datos es SQL Server Compact 4.0):
Dim competitor=context.Competitors.Find(id)
Cuando perfilo esto, el método Find tarda más de 300 ms para recuperar al competidor de una tabla de solo 60 registros.
Cuando cambio el código a:
Dim competitor=context.Competitors.SingleOrDefault(function(c) c.ID=id)
Entonces el competidor se encuentra en solo 3 ms.
La clase Competidor:
Public Class Competitor
Implements IEquatable(Of Competitor)
Public Sub New()
CompetitionSubscriptions = New List(Of CompetitionSubscription)
OpponentMeetings = New List(Of Meeting)
GUID = GUID.NewGuid
End Sub
Public Sub New(name As String)
Me.New()
Me.Name = name
End Sub
''ID''
Public Property ID As Long
Public Property GUID As Guid
''NATIVE PROPERTIES''
Public Property Name As String
''NAVIGATION PROPERTIES''
Public Overridable Property CompetitionSubscriptions As ICollection(Of CompetitionSubscription)
Public Overridable Property OpponentMeetings As ICollection(Of Meeting)
End Class
Definí las relaciones de muchos a muchos para CompetitionSubscriptions
y OpponentMeetings
usando la API fluida.
La propiedad de ID de la clase Competitor
es una Longitud que se traduce por Código primero en una columna de Identidad con una clave principal en la tabla de datos (SQL Server Compact 4.0)
¿¿Que esta pasando aqui??
Find
llamadas DetectChanges
internamente, SingleOrDefault
(o, en general, cualquier consulta) no lo hace. DetectChanges
es una operación costosa, por lo que Find
es más lento (pero puede volverse más rápido si la entidad ya está cargada en el contexto porque Find
no ejecutará una consulta sino que solo devolverá la entidad cargada).
Si desea utilizar Find
para muchas entidades, por ejemplo en un bucle, puede desactivar la detección automática de cambios de esa manera (no se puede escribir en VB, por lo tanto, un ejemplo de C #):
try
{
context.Configuration.AutoDetectChangesEnabled = false;
foreach (var id in someIdCollection)
{
var competitor = context.Competitors.Find(id);
// ...
}
}
finally
{
context.Configuration.AutoDetectChangesEnabled = true;
}
Ahora, Find
no llamará a DetectChanges
con cada llamada y debería ser tan rápido como SingleOrDefault
(y más rápido si la entidad ya está conectada al contexto).
La detección automática de cambios es un tema complejo y algo misterioso. Una gran discusión detallada se puede encontrar en esta serie de cuatro partes:
(Enlace a la parte 1, los enlaces a las partes 2, 3 y 4 están al principio de ese artículo)
http://blog.oneunicorn.com/2012/03/10/secrets-of-detectchanges-part-1-what-does-detectchanges-do/