EntitySet и foreach

Дата: 31.07.2010
Категории: ASP.NET MVC Visual Studio (C#)

Имеется MVC приложение. При добавлении в проект объекта LINQ to SQL Classes, формируется набор классов, позволяющих работать с базой данных.

В случае если между таблицами БД имеются отношения (Relationships), то получая элемент из одной таблицы, мы сможем получить связанные с ним данные.

База данных

Предположим имеется две таблицы в базе данных. Таблицы связаны между собой.

LINQ

Описание проблемы

Таблицы связанны «один ко многим» и, получив элемент из таблицы Company, мы сможем получить из таблицы Product список всех связанных данных. Но данные будут предоставлены не в виде списка List или IEnumerable, а в виде EntitySet. Вообще работа с ним точно такая же как и со списком, за исключением того, что обращаться к содержимому списка из представления (View) не получается. Компилятор выдает ошибку.

Мне понадобилось вывести все данные из таблицы Company, а под каждым элементом данных вывести поле Name из таблицы Product (по связи).

Т.е. я написал что-то вроед этого (естественно, передав нужные данные в контроллере):

<% foreach (var item in (IEnumerable<Company>)ViewData["Company"])
   { %>
      <p><%: item.CompanyName %></p>
      // А тут еще один foreach, но уже пробегаем item.Products
<% } %>

Но тут компилятор выдает ошибку:

foreach statement cannot operate on variables of type 'System.Data.Linq.EntitySet'
because 'System.Data.Linq.EntitySet' does not contain a public definition
for 'GetEnumerator'

Но что самое интересное, в контроллере я мог выполнить подобные действия (обратиться к данным таким образом).

Преобразовать EntitySet в тот же List в самом представлении (при выводе)  не получалось — ошибка.

Решение 1

К сожалению это решение я нашел гораздо позже чем второе. Но оно оказалось самым простым и лучшим. Я всегда говорил всем знакомым и друзьям «Читайте тексты ошибок, читайте внимательно документацию и т.д.», но сам этого в этом случае не сделал. В тексте ошибки черным по белому написано, что нужно сделать. Дак вот, нужно добавить в Web.config в раздел assemblies следующую строку:

<add assembly="System.Data.Linq, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>

И всего-то…

Решение 2

Это решение было первым которое я нашел. Поскольку в контроллерах я могу работать с EntitySet, значит я могу его и преобразовать в List. А во View можно будет пробежать список List.

Я создал публичный класс, а в нем метод в который передавал объект типа Company. Затем преобразовывал Products у переданного объекта.

public static class EntitySetToList
{
  public static List<Product> Convert(Company company)
  {
    return company.Products.ToList<Product>();
  }
}

В результате код в представлении стал таким:

<% foreach (var item in (IEnumerable<Company>)ViewData["Company"])
   { %>
      <p><%: item.CompanyName %></p>
      <% foreach (var item2 in EntitySetToList.Convert(item))
         { %>
            <p>Продукт <%: item2.Name %></p>
      <% } %>
<% } %>

В принципе все просто. Вызываем написанную функцию в представлении, преобразовываем, и работаем уже со списком List.

Удачи…

Коментарии:

  1. msi:
    06.08.2010 в 16:36

    Вообще-то такой метод передачи данных в представление (View) не совсем хорошо

    <% foreach (var item in (IEnumerable)ViewData[«Company»])%>

    для этих целей лучше делать строготипизированное представление и потом бежать по Model

    Так будет более наглядно, улучшит как читабельность, так и сопровождение кода в случае изменения каких-то полей в модели.

  2. 06.08.2010 в 20:45

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