Слишком много вызовов базы данных при сопоставлении с ViewModel - PullRequest
1 голос
/ 11 апреля 2011

Привет всем, меня убивают запросы к базе данных в моем приложении MVC3, когда я сопоставляю свой репозиторий с моделью представления.Представление довольно сложное, основным объектом является Assignment, но оно также возвращает данные из нескольких своих отношений.Режим просмотра выглядит следующим образом

    public int Id { get; set; }
    public DateTime? RelevantDate { get; set; }
    public String Name { get; set; }
    public String ProcessName { get; set; }
    public String Status { get; set; }
    public String Assignee { get; set; }
    public int AssigneeId { get; set; }
    public bool HasAttachment { get; set; }
    public bool IsGroupAssignee { get; set; }
    public bool Overdue { get; set; }
    public List<String> AvailableActions { get; set; }
    public Dictionary<String, String> AssignmentData { get; set; }
    public Dictionary<String, String> CompletionData { get; set; }
    public List<Transactions> Comments { get; set; }
    public List<Transactions> History { get; set; }
    public List<File> Files { get; set; }

Там много чего происходит, но все данные имеют отношение к представлению.В моем репозитории я явно загружаю все необходимые отношения с помощью .Include (я использую Entity Framework), но данные на самом деле не загружаются, пока я не начну перебирать список.

var _assignments = (from ctx.Assignments
                  .Include("Process").Include("Files")
                  .Include("AssignmentDataSet")
                  .Include("Transactions")
                  .where w.Tenant.Id == _tenantId  
                  select w);

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

Теперь вот где я проверяю транзакции базы данных.Я должен получить эти данные в ViewModel, чтобы я мог их отобразить.

private IList<AssignmentViewModel> CreateViewModel(IEnumerable<Assignment> aList)
    {
        var vList = new List<AssignmentViewModel>();

        foreach (var a in aList)
        {
            var assigneeId = a.Assignee;
            vList.Add(new AssignmentViewModel()
                          {
                              Id = a.Id,
                              AssigneeId = (int) a.Assignee,
                              HasAttachment = (a.Files.Count > 0),
                              Name = a.Name,
                              IsGroupAssignee = a.AssignedToGroup,
                              ProcessName = a.Process.Name,
                              RelevantDate = a.RelevantDate,
                              Status = a.Status,
                              AvailableActions = _assignmentRepository.GetAvailableActions(_user, a),
                              Assignee =
                                  _users.Where(i => i.Id == assigneeId).Select(v => v.FullName).
                                  FirstOrDefault(),
                              AssignmentData =
                                  a.AssignmentDataSet.Where(st => st.State == "Assign").ToDictionary(
                                      d => d.Name, d => d.Value),
                              CompletionData = a.AssignmentDataSet.Where(st => st.State == "Complete").ToDictionary(
                                  d => d.Name, d => d.Value),
                              Comments = a.Transactions.Where(t => t.Action == "New Comment").ToList(),
                              History = a.Transactions.Where(t => t.Action != "New Comment").ToList(),
                              Overdue =
                                  a.RelevantDate >= DateTime.UtcNow.AddHours(-5) || a.RelevantDate == null ||
                                  a.Status == "Complete" || a.Status == "Canceled"
                                      ? false
                                      : true
                          });


        }

        return vList;
    }

В результате получается около 2,5 дБ запросов на Assignment.Это представление вернет максимум 30 результатов.Это много хитов в моей базе данных.Излишне говорить, что страница очень медленная.Время отклика 5-7 секунд.Я смущен этим!Я просто пытаюсь сделать здесь слишком много, или я просто делаю это неправильно?

Как я могу оптимизировать это?

1 Ответ

3 голосов
/ 11 апреля 2011

Я вижу две вещи:

HasAttachment = (a.Files.Count > 0),

Просто используйте взамен Any(), чтобы вам не приходилось перебирать все файлы, предполагая, что это все еще IEnumerable:

HasAttachment = a.Files.Any(),

Другая вещь - это комментарии и история:

Comments = a.Transactions.Where(t => t.Action == "New Comment").ToList(),
History = a.Transactions.Where(t => t.Action != "New Comment").ToList(),

Вы можете объединить эти вызовы, материализовав полный список перед созданием AssignmentViewModel, а затем просто взять соответствующие части:

var transactions = a.Transactions.ToList();
vList.Add(new AssignmentViewModel()
{
  ..
  Comments = transactions.Where(t => t.Action == "New Comment").ToList(),
  History = transactions.Where(t => t.Action != "New Comment").ToList(), 
}

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

...