Мы используем Entity Framework 4.2 с использованием первого подхода модели и генерации кода DbContext.Асинхронные запросы и ленивая загрузка в Entity Framework
Допустим, мы имеем следующие модели данных в рамках объекта:
class Person
{
public string Name { get; set; }
public Address Address { get; set; }
}
class Address
{
public string City; { get; set; }
}
Сценарий следующий:
- ViewModel хочет загрузить некоторые данные из базы данных
- Задача (асинхронной операция) создается для загрузки данных. Это состоит в том, что мы не хотим, чтобы пользовательский интерфейс зависал при загрузке данных.
- Задача (которая выполняется в отдельном потоке) создает новый контекст базы данных и загружает данные (например, объект Person) из базы данных
- Завершено завершение работы и контекст базы данных.
- Основная тема сообщается о завершении задачи. Основной поток может теперь получить доступ к объекту Person.
- Вид пытается показать имя и адрес человека в текстовом поле через привязку данных
- Точки зрения не обращается к Person.Name (никаких проблем здесь)
- Вида Допуски Person.Address.City -> OOPS! Контекст базы данных уже был удален (поскольку загрузка выполнялась в отдельном потоке) и из-за ленивой загрузки Person.Address недоступен!
В фазе 3 человек загружен в следующим образом:
using (DatabaseContext context = new DatabaseContext())
{
Person person = from p in context.Persons.FirstOrDefault();
return person;
}
Хорошо, я знаю, что (в теории) я мог бы заставить загрузку объекта Адрес двумя способами: 1) Использование DbSet.Include, например:
context.Persons.Include("Address").FirstOrDefault();
2) Person.Address Access в то время как контекст базы данных все еще жив, поскольку это заставит адрес должен быть загружен
Person person = context.Persons.FirstOrDefault();
Address address = person.Address;
return person;
Конечно, первые из них является предпочтительным решением, потому что это не так, как некрасиво второго (только доступ к свойству, чтобы заставить загрузку данных, а затем отбрасывания результата некрасиво). Кроме того, в случае сбора (например, списка лиц) мне пришлось бы прокручивать коллекцию и получать доступ к Адресу отдельно для каждого человека. Проблема с первым решением заключается в том, что только DbSet имеет метод Include, а все другие коллекции, возвращенные из запросов, не имеют. Так, скажем, у меня есть следующие структуры базы данных
class Resource {}
class Person : Resource { public Address Address { get; set; } }
class Appointment { public IList<Resource> Resources { get; set; } }
и я хочу, чтобы загрузить все конкретные назначения и включают в себя адрес в каждом ресурсе, который человек, я в беде (или, по крайней мере, я не мог найти способ, чтобы написать запрос для него). Это связано с тем, что context.Appointments.Resources не относится к типу DbSet, а к ICollection, который не имеет метода Include. (Хорошо, возможно, в этом случае я мог бы написать запрос, как-то, начиная с контекста. Персоны вместо контекста.Назначения, так что я мог бы использовать Include но есть много сценариев, где это невозможно)
Так в основном вопросы, которые:
- Является ли это правильный способом сделать асинхронный доступ к базе данных в первое место?
- Как решить проблемы с ленивой загрузкой? Поворот ленивой загрузки не является решением (если только это не может быть сделано только для конкретных организаций?)