Итерация анонимных типизированных данных в представлении MVC

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

            var projectData = from p in db.Projects
                          orderby p.title
                          select new
                          {
                              Title = p.title,
                              DevURL = p.devURL ?? "N/A",
                              QAURL = p.qaURL ?? "N/A",
                              LiveURL = p.liveURL ?? "N/A",
                              Users = p.GetUsers().MakeUserList()
                          };

        ViewData["ProjectSummary"] = projectData;

Как мне выполнить итерацию по этим данным представления в представлении MVC во внешнем интерфейсе, чтобы сказать, составить таблицу результатов?


person Chris James    schedule 12.11.2008    source источник
comment
Я на стороне Марка и Уилла. Использование реальных классов модели для инкапсуляции данных модели и бизнес-логики делает код более разборчивым и легким в обслуживании с очень небольшими затратами на создание класса (что в любом случае необходимо при проектировании, ориентированном на предметную область).   -  person Charles Chen    schedule 02.06.2009


Ответы (3)


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

Проблема, с которой вы столкнулись, заключается в том, что ваш анонимный тип приводится к объекту, когда он хранится в ViewData. Со стороны пользовательского интерфейса, когда вы извлекаете этот объект, единственный способ получить доступ к его свойствам - использовать отражение. Вы НЕ хотите делать это в своем пользовательском интерфейсе. Это будет в высшей степени некрасиво. Вместо этого просто добавьте в свои модели следующий класс:

public class Project{

public string Title {get;set;}
public string DevUrl {get;set;}
public string QAUrl {get;set;}
public string LiveUrl {get;set;}
public IEnumerable<User> Users {get;set;}

public static IEnumerable<Project> RetrieveAllProjects()
{
  return from p in db.Projects
           orderby p.title
           select new Project
             {
                Title = p.title,
                DevURL = p.devURL ?? "N/A",
                QAURL = p.qaURL ?? "N/A",
                LiveURL = p.liveURL ?? "N/A",
                Users = p.GetUsers().MakeUserList()
             };
}

В вашем контроллере сделайте это:

public ActionResult Index()
{
  return View("Index", Project.RetrieveAllProjects());
}

и в коде вашего представления строго введите его так:

//snip
public partial class Index : ViewPage<IEnumerable<Project>>
{
//snip

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

Кроме того, модель - отличное место (и, по сути, должно быть там, где вы это делаете), чтобы разместить логику для загрузки ваших данных и построения самих моделей. Подумайте об ActiveRecord. И пока вы все это кодируете, поймите, что такие проекты, как SubSonic, создают ваши модели без лишних хлопот и суеты.

person Community    schedule 12.11.2008
comment
Спасибо за ответ, Уилл. Я понимаю вашу точку зрения, я как бы надеялся, что смогу каким-то образом использовать анонимные типы в моем внешнем коде, но я думаю, что не без излишней чистоты. Я ненавижу делать классы отображения :) - person Chris James; 12.11.2008
comment
Ваши классы отображения должны инкапсулировать логику загрузки для этих классов. Вы не должны загружать данные в свои контроллеры; этого нет в их должностных инструкциях. Так что не стоит считать их мусором ... - person ; 12.11.2008

Не пробовал это с анонимным типом, но я так делаю, передавая объект List<T> в ViewData

<% foreach (Project p in (IEnumerable<Project>)ViewData["ProjectSummary"]) { %>
     <%= Html.Encode(p.Title) %>
<% } %>

Надеюсь, это то, что вы ищете.

отметка

person Community    schedule 23.11.2008

Проблема не в том, что это анонимный тип. Проблема в том, что это просто объект IQueryable ‹> с отложенной оценкой, и он еще не оценивался.

Я не могу ответить за ASP.NET MVC, но в очень похожем монорельсе вам придется преобразовать его из итератора в реальную коллекцию:

        var projectData = (from p in db.Projects
                      orderby p.title
                      select new
                      {
                          Title = p.title,
                          DevURL = p.devURL ?? "N/A",
                          QAURL = p.qaURL ?? "N/A",
                          LiveURL = p.liveURL ?? "N/A",
                          Users = p.GetUsers().MakeUserList()
                      }).ToList();
person James Curran    schedule 12.11.2008