Подтвердить что ты не робот

Метод DbSet.Find смехотворно медленный по сравнению с .SingleOrDefault для ID

У меня есть следующий код (база данных SQL Server Compact 4.0):

Dim competitor=context.Competitors.Find(id)

Когда я просматриваю это, метод Find принимает 300 + ms для извлечения участника из таблицы всего из 60 записей.

Когда я меняю код на:

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

Затем конкурент находится всего за 3 мс.

Класс конкурента:

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

Я определил отношение многих ко многим для CompetitionSubscriptions и OpponentMeetings, используя свободный API.

Свойство ID класса Competitor - это Long, которое переводится с помощью кода First в столбец Identity с первичным ключом в datatable (SQL Server Compact 4.0)

Что здесь происходит?

4b9b3361

Ответ 1

Find вызывает DetectChanges внутренне, SingleOrDefault (или вообще любой запрос) нет. DetectChanges является дорогостоящей операцией, поэтому причина, по которой Find работает медленнее (но может стать быстрее, если объект уже загружен в контекст, потому что Find не будет запускать запрос, а просто возвращает загруженный объект).

Если вы хотите использовать Find для большого количества объектов - например, в цикле - вы можете отключить автоматическое обнаружение изменений так (не можете записать его в VB, поэтому пример С#):

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

Теперь Find не будет вызывать DetectChanges с каждым вызовом, и он должен быть таким же быстрым, как SingleOrDefault (и быстрее, если объект уже привязан к контексту).

Автоматическое обнаружение изменений является сложным и несколько загадочным предметом. Подробное обсуждение можно найти в этой серии из четырех частей:

(Ссылка на часть 1, ссылки на части 2, 3 и 4 находятся в начале этой статьи)

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