Связывание данных 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.
Это не отвечает, ПОЧЕМУ они внесли это изменение, но по крайней мере я вижу, что есть причина, по которой он будет работать в более старой версии.