2016-06-13 2 views
0

Итак, я создаю веб-приложение для отображения информации о академических предложениях моего студенческого городка. Предполагается, что сайт должен ленить загрузку списка программ на основе некоторых выбранных пользователем критериев.Сложные сущности Framework Отношения и проблема сортировки

Проблема, с которой я столкнулся, заключается в том, как правильно сортировать данные в совокупности со сложным набором ассоциаций.

В основе модели лежит довольно простой класс программы.

public abstract class Program 
{ 

    public Program() 
    { 
     ProgramDegrees = new HashSet<ProgramDegree>(); 
     ProgramOptions = new HashSet<ProgramOption>(); 
     Keywords = new HashSet<Keyword>(); 
     Departments = new HashSet<Department>(); 
    } 

    [Key] 
    public int Id { get; set; } 

    [Required] 
    [StringLength(100)] 
    public string Name { get; set; } 

    //...some virtual navigation properties go here 

}

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

 Programs = Programs.OrderBy(p => p.Name).Skip(cardsStartIndex ?? 0).Take(15); 

Что расцепления меня это ProgramOptions и как заказать их наряду с программами в алфавитном порядке. Варианты в основном представляют собой суб-поле или акцент в рамках академической программы, такой как опция «Иллюстрация» в программе «Дизайн».

public partial class ProgramOption : AbstractProgram 
{ 
    [Key] 
    public int Id { get; set; } 

    [Required] 
    [StringLength(100)] 
    public string Name { get; set; } 

    public virtual Program Program { get; set; } 
} 

Я сопоставить отношения в моем контексте данных с использованием Fluent API

 modelBuilder.Entity<Program>() 
      .HasMany(e => e.ProgramOptions) 
      .WithRequired(e => e.Program) 
      .WillCascadeOnDelete(false); 

В пользовательском интерфейсе, мы листинг ProgramOptions прямо рядом с самими программами. Все хорошо и хорошо. Когда у меня есть список программ, соответствующих любым критериям поиска, я просто добавляю ProgramOptions, связанные с каждой программой, в View Model.

Только одна проблема для подростков. Несмотря на то, что я сортирую Программы, найденные по их имени, так что они отображаются в алфавитном порядке, добавив ProgramOptions в после того, как факт означает, что данный параметр всегда отображает вместе с его программой, даже если имя параметра должно быть в алфавитном порядке в другом месте списка , Это делает список менее полезным, если вы просматриваете определенный заголовок. I может просто вручную сортировать окончательный список в Модели просмотра, , за исключением, что дизайн пользовательского интерфейса требует эффекта infinite scroll. Поэтому, даже если первая загрузка была в алфавитном порядке, следующих 15 или около того объектов не было бы.

Моя первая мысль заключалась в использовании шаблона наследования (сделать ProgramOptions подклассом Программ или какого-либо третьего класса AbstractPrograms), но это оказалось намного сложнее, чем его ценность, учитывая все остальные ассоциации.

Единственное, что я могу придумать, это выбрать все программы из базы данных, построить соответствующие ViewModel для всех из них и их варианты, а затем взять номер, который я хочу включить при следующем загрузке. Мне это не нравится, потому что он более или менее поражает половину цели ленивой загрузки (извлечения данных из БД за один раз и доведение их до клиента по частям).

Есть ли решение или образец, который я здесь просматриваю?

+0

«Несмотря на то, что я сортирую Программы, найденные по их имени, так что они отображаются в алфавитном порядке, добавив ProgramOptions в после того, как факт означает, что данный параметр всегда отображается рядом с его программой« Мне трудно представить визуализацию проблемы. Я думаю, вопрос в том, что если у вас есть решение уже (просто не ленивая загрузка), зачем тратить циклы на поиск другого решения? Вы можете либо загружать, либо просто выдать отдельный запрос для параметров самостоятельно, либо использовать ajax и т. Д. Как формулируется вопрос, это похоже на проблему с пользовательским интерфейсом. – DVK

+0

Я имею в виду «ленивую загрузку» в смысле пользовательского интерфейса, а не в смысле контекста данных. Я думаю, что это также называется «Бесконечный свиток». В основном, я загружаю группы вычисленных результатов. – jonnybot

+0

Я думаю, что мне нужна реализация синтаксиса 'Join', аналогичная http://stackoverflow.com/questions/5010110/entityframework-join-using-join-method-and-lambdas или http: // stackoverflow.com/questions/10222255/entity-framework-4-what-is-the-syntax-for-joining-2-tables-then-paging-them – jonnybot

ответ

0

Обычно, если вы попадаете в подобную ситуацию, это знак того, что вы загружаете слишком много вперед. В основном, ваша проблема заключается в том, что вы загружаете всю модель данных при начальной загрузке страницы, но вы не знаете, какие ProgramOptions вы хотите отобразить (или в каком порядке) до конца. Вместо решения проблемы сортировки сложных объектных моделей я бы разбил ее на более простые компоненты.

Это не специально помечено, но на основе вашего описания это похоже на то, что вы находитесь в приложении MVC. Я бы добавил обратный вызов ajax, когда выбрана программа, которая загружает ProgramOptions (в отсортированном порядке) для этой программы. На стороне сервера это, вероятно, должно быть сильно кэшировано или даже предварительно рассчитано для каждой программы, если это необходимо.

Если вы не заперты в MVC, это именно та проблема, которую Angular + WebApi действительно решают.

+0

Это приложение MVC. – jonnybot

0

Наконец понял, что я переусердствовал.

 var joinedProgramOptions = Programs.AsEnumerable().SelectMany(p => 
     { 
      if (p.ProgramOptions.Any()) 
      { 
       return p.ProgramOptions.Select(po => new { Prog = p, ProgOpt = po }); 
      } 
      int[] dummy = new int[] { 0 }; 
      return dummy.Select(d => { 
       return new { Prog = p, ProgOpt = p.ProgramOptions.FirstOrDefault() }; 
      }); 
     }); 

     joinedProgramOptions = joinedProgramOptions 
      .OrderBy(jq => jq.ProgOpt?.Name ?? jq.Prog.Name) 
      .Skip(cardsStartIndex ?? 0) 
      .Take(15); 

     List<ProgramViewModel> cards = joinedProgramOptions.Select(hybridObject => 
      new ProgramViewModel() 
      { 
       Title = hybridObject.ProgOpt?.Name ?? hybridObject.Prog.Name, 
       OptionOf = hybridObject.ProgOpt?.Program, 
       Degrees = hybridObject.Prog.ProgramDegrees, 
       Departments = hybridObject.Prog.Departments 
      } 
     ).ToList(); 

Да, отбрасывая его перечислимого с AsEnumerable означает, что база данных не делает заказ, но я думаю, что я в порядке с этим.

Смежные вопросы