web-dev-qa-db-fra.com

Méthode DbSet.Find ridiculement lente par rapport à .SingleOrDefault sur ID

J'ai le code suivant (la base de données est SQL Server Compact 4.0):

Dim competitor=context.Competitors.Find(id)

Lorsque je présente ce profil, la méthode Find prend 300 + ms pour récupérer le concurrent à partir d'une table de seulement 60 enregistrements.

Lorsque je change le code en:

Dim competitor=context.Competitors.SingleOrDefault(function(c) c.ID=id)

Ensuite, le concurrent se retrouve en seulement 3 ms.

La classe Concurrent:

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

J'ai défini les relations plusieurs à plusieurs pour CompetitionSubscriptions et OpponentMeetings à l'aide de l'API couramment.

La propriété ID de la classe Competitor est un Long qui est traduit par Code First dans une colonne Identity avec une clé primaire dans le datatable (SQL Server Compact 4.0)

Qu'est-ce qui se passe ici??

34
Dabblernl

Find appelle DetectChanges en interne, SingleOrDefault (ou généralement n'importe quelle requête) ne le fait pas. DetectChanges est une opération coûteuse, c'est pourquoi Find est plus lent (mais il peut devenir plus rapide si l'entité est déjà chargée dans le contexte car Find n'exécuterait pas requête mais juste renvoyer l'entité chargée).

Si vous souhaitez utiliser Find pour un grand nombre d'entités - dans une boucle par exemple - vous pouvez désactiver la détection automatique des modifications comme cela (vous ne pouvez pas l'écrire en VB, donc un exemple C #):

try
{
    context.Configuration.AutoDetectChangesEnabled = false;
    foreach (var id in someIdCollection)
    {
        var competitor = context.Competitors.Find(id);
        // ...
    }
}
finally
{
    context.Configuration.AutoDetectChangesEnabled = true;
}

Maintenant, Find n'appellera pas DetectChanges à chaque appel et il devrait être aussi rapide que SingleOrDefault (et plus rapide si l'entité est déjà attachée au contexte).

La détection automatique des modifications est un sujet complexe et quelque peu mystérieux. Une grande discussion détaillée se trouve dans cette série en quatre parties:

(Lien vers la partie 1, les liens vers les parties 2, 3 et 4 sont au début de cet article)

http://blog.oneunicorn.com/2012/03/10/secrets-of-detectchanges-part-1-what-does-detectchanges-do/

55
Slauma