Связывание данных Webforms с ошибкой запроса EF Code-First Linq

В этом примере здесь Скотт показывает выполнение запроса Linq к dbContext и привязывает результат непосредственно к GridView, чтобы показать список продуктов. В его примере используется версия CTP4 для кода First.

Однако, когда я пытаюсь сделать то же самое, используя последнюю версию EntityFramework 4.1, я получаю следующую ошибку:

Связывание данных непосредственно с запросом хранилища (DbSet, DbQuery, DbSqlQuery) не поддерживается. Вместо этого заполните DbSet данными, например вызов Load на DbSet, а затем привязка к локальным данным.

Я вижу, что объект DBQuery специально ставит эту ошибку в своей реализации IListSource.GetList(), которая используется в привязке данных.

Любые идеи, почему его пример работает? Кстати, я знаю, что могу сделать эту работу, поставив projects.ToList(). Мой главный вопрос: изменилось ли что-то в версии выпуска, что делает этот тип вещей более неработоспособным, или я что-то упустил где-нибудь, что может обойти эту ошибку.

Просто для справки, я имею в виду код вроде этого:

MyDbContext db = new MyDbContext();

var projects = from p in db.Projects
               where p.AnotherField == 2
               select p;

grdTest.DataSource = projects;
grdTest.DataBind();

Ответ 1

Это долгая история, но я постараюсь не сделать ее скучной.

В первой версии EF мы поддерживали привязку непосредственно к запросам. Мы заслужили достаточный опыт в отношении подводных камней и путаницы в том, что это привело к тому, что мы решили явно отключить новый API, который мы создали для EF 4.1. Основная проблема для меня заключалась в том, что инфраструктура привязки данных WinForms и WPF предполагает, что источники данных находятся в памяти и недороги для доступа. Это привело к тому, что привязка данных часто запрашивала список привязки более одного раза. В EF привязка к повторному запросу обязательно подразумевает необходимость получения последних результатов из базы данных, поэтому мы сделали так, чтобы каждый раз, когда список привязок запрашивался, мы повторно выполняем запрос к базе данных. Это вызвало по меньшей мере два выполнения запросов каждый раз, когда кто-либо связан с запросом.

Было несколько других аспектов привязки к запросам, которые были довольно запутанными или противоречивыми для многих клиентов. Я изучаю, как все работает в этом блоге: http://blogs.msdn.com/b/diego/archive/2008/10/09/quick-tips-for-entity-framework-databinding.aspx

То, что вы должны делать с DbContext API, - это привязка к локальным данным напрямую, а не к запросам. Для этого мы открываем DbSet.Local, который является ObservableCollection, который хорошо работает для WPF и метода ToBindingList, который обертывает коллекцию в BindingList для более легкого использования в WinForms.

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

Надеюсь, что это поможет

Ответ 2

Перешел по той же проблеме и нашел эту тему. ToList() работал:

using (NorthwindContext context = new NorthwindContext())
{
    var products = from p in context.Products
                   where p.Discontinued == false
                   select p;

    gridView.DataSource = products.ToList();
    gridView.DataBind();
}

Ответ 3

При взгляде на DLL-версию EF4 Feature CTP4 в Reflector я вижу, что его объект DBQuery не реализует IListSource.GetList() и генерирует исключение, как это делает dll EF 4.1. Я предполагаю, что где-то вдоль линии у них была причина перестать разрешать привязку непосредственно к запросу, хотя она реализует IEnumerable.

Это не отвечает, ПОЧЕМУ они внесли это изменение, но по крайней мере я вижу, что есть причина, по которой он будет работать в более старой версии.