Помогите мне разобраться в кешировании Entity Framework 4 для отложенной загрузки - PullRequest
2 голосов
/ 28 апреля 2010

Я получаю неожиданное поведение с помощью Entity Framework 4.0, и я надеюсь, что кто-то может помочь мне понять это. Я использую базу данных Northwind для целей этого вопроса. Я также использую генератор кода по умолчанию (не Poco или самообследование). Я ожидаю, что каждый раз, когда я запрашиваю контекст для структуры, чтобы совершить туда и обратно, только если я еще не извлек эти объекты. Я получаю такое поведение, если отключаю ленивую загрузку. В настоящее время в моем приложении я кратко включаю ленивую загрузку, а затем выключаю ее, чтобы получить желаемое поведение. Это довольно много, так что, пожалуйста, помогите. Вот хороший пример кода, который может продемонстрировать мою проблему.

Public Sub ManyRoundTrips()
    context.ContextOptions.LazyLoadingEnabled = True
    Dim employees As List(Of Employee) = context.Employees.Execute(System.Data.Objects.MergeOption.AppendOnly).ToList()

    'makes unnessesary round trip to the database, I just loaded the employees'
    MessageBox.Show(context.Employees.Where(Function(x) x.EmployeeID < 10).ToList().Count)
    context.Orders.Execute(System.Data.Objects.MergeOption.AppendOnly)
    For Each emp As Employee In employees
        'makes unnessesary trip to database every time despite orders being pre loaded.'
        Dim i As Integer = emp.Orders.Count
    Next
End Sub

Public Sub OneRoundTrip()
    context.ContextOptions.LazyLoadingEnabled = True
    Dim employees As List(Of Employee) = context.Employees.Include("Orders").Execute(System.Data.Objects.MergeOption.AppendOnly).ToList()

    MessageBox.Show(employees.Where(Function(x) x.EmployeeID < 10).ToList().Count)

    For Each emp As Employee In employees
        Dim i As Integer = emp.Orders.Count
    Next
End Sub

Почему первый блок кода выполняет необычные циклические обходы?

Ответы [ 2 ]

3 голосов
/ 28 апреля 2010

Ваши ожидания не верны. Запросы всегда запрашивают БД. Всегда. Это потому, что LINQ всегда конвертируется в SQL.

Чтобы загрузить объект из контекста, если он уже получен, и из БД, если это не так, используйте ObjectContext.GetObjectByKey () .

2 голосов
/ 29 апреля 2010

Требуется первая «ненужная» поездка - вы сделали новый запрос, и база данных могла измениться за это время. Если вместо этого вы использовали переменную сотрудников (в которой вы сохранили результат запроса), вам не нужно совершать поездку в базу данных.

Второй необходим, потому что вы просите его получить Заказы для каждого Сотрудника. При отложенной загрузке и отсутствии функции Include () он не считывает заказы, пока вы не попросите об этом с помощью emp.Orders.Count ().

Помните, что до тех пор, пока вы не начнете выполнять итерацию по запросу (или вызвать какой-либо метод, который требует его повторения), LINQ to EF ничего не делает. Если вы сохраните этот запрос в переменной, а затем вызовете .Count () для него, произойдет возврат в оба конца. Если вы воспользуетесь тем же запросом и начнете перечислять его, произойдет еще одна поездка туда и обратно. Если у сущностей в этом запросе есть отношения, и ленивая загрузка включена каждый раз, когда вы обращаетесь к ней, будет еще одна поездка туда и обратно.

Ваш второй пример показывает, как сделать это правильно, если вы заранее знаете, что хотите получить ордера, это нетерпеливая загрузка . Обратите внимание, что вы не возвращаетесь к контексту, чтобы снова спросить сотрудников, вы снова используете уже загруженный.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...