映射到ViewModel时,数据库调用太多

时间:2011-04-11 04:35:06

标签: asp.net-mvc linq entity-framework asp.net-mvc-3 entity

嘿大家,当我将我的存储库映射到View Model时,我的MVC3应用程序中的数据库查询被杀了。 View非常复杂,主要对象是Assignment,但View也会从其中的一些关系中返回数据。查看模式看起来像这样

    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; }

那里有很多东西,但所有数据都与View相关。在我的存储库中,我使用.Include显式加载了所有必需的关系(我正在使用实体框架),但是在我开始遍历列表之前,数据实际上并未加载。

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;
    }

这导致每Assignment个大约2.5分贝的查询。此视图最多可返回30个结果。这对我的数据库有很多打击。不用说,页面很慢。响应时间为5-7秒。我很尴尬!我只是想在这里做太多,或者我只是做错了?

如何优化此功能?

1 个答案:

答案 0 :(得分:3)

我能看到两件事:

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(), 
}

如果您必须支持这种显示数据的方式,您应该考虑数据库中的一个视图和相应的实体,它使用连接为您选择所有或大多数相应的数据,因此您需要花费大量精力来UI的数据要少得多。