数据库查询效率和将业务逻辑从控制器移到辅助查询/过滤器

时间:2016-08-23 07:30:24

标签: asp.net asp.net-mvc asp.net-mvc-5

当前项目:

  • ASP.NET 4.5.2
  • MVC 5

我有一个奇怪的问题,但我正在努力提高代码的效率。

现在我是:

  1. 将数据从数据库中拉出到该表的模型中,然后
  2. 将其填充到一个非常有限的“格式化模型”中(其中包含数据库表的一小部分字段,但在根据用户显示之前需要操作数据),然后
  3. 嵌入在视图模型中。
  4. 我没有将DB密集型过程放入视图中,因为渲染速度取决于它;因此,“格式化模型”根据用户类别(只有2个)进行数据呈现决策,正在访问消息传递系统。

    我也试图一般遵循“胖模型,瘦控制器”范例,但我并没有花太多时间去做。更重要的是,我试图尽可能多地将业务逻辑推送到模型中,我觉得这比明确拥有一个瘦控制器更重要。

    第1步很简单:

    var UserId = User.Identity.GetUserId();
    var UserRole = User.IsInRole("HEO");
    IEnumerable<Messaging> data = await db.Messaging
      .Where(x => x.MessageTo == UserId && (UserRole ? x.MsgSender.RecruiterProfile.ProfileActive : x.MsgSender.HEOProfile.ProfileActive))
      .OrderByDescending(x => x.MessageSent)
      .ToListAsync();
    

    “拉取用户是收件人的所有邮件,并将列表限制为发件人在系统上仍处于活动状态的位置;按发送日期排序。“

    然后我填写“格式化模型”:

    InboxViewModel model = new InboxViewModel(data, UserRole);
    

    看起来像这样:

    public class MessageListModel {
      public Guid MessageId { get; set; }
      public bool MessageRead { get; set; }
      public string MessageName { get; set; }
      public string MessageSubject { get; set; }
      public string MessageSent { get; set; }
    }
    public class InboxViewModel {
      public IEnumerable<MessageListModel> Inbox { get; set; }
      public InboxViewModel() { }
      public InboxViewModel(IEnumerable<Messaging> data, bool UserRole) {
        Inbox = data.Select(x => new MessageListModel {
            MessageId = x.MessageId
          , MessageRead = (x.MessageRead != null ? true : false)
          , MessageName = (UserRole ? (x.MsgSender.RecruiterProfile.CompanyName.Length > 16 ? x.MsgSender.RecruiterProfile.CompanyName.Substring(0, 16) + "…" : x.MsgSender.RecruiterProfile.CompanyName) : (x.MsgSender.HEOProfile.UsualName.Length > 32 ? x.MsgSender.HEOProfile.UsualName.Substring(0, 32) + "…" : x.MsgSender.HEOProfile.UsualName))
          , MessageSubject = (x.MessageSubject.Length > 64 ? x.MessageSubject.Substring(0, 64) + "…" : x.MessageSubject)
          , MessageSent = x.MessageSent.ToString("yyyy-MM-dd")
        }).ToList();
      }
    }
    

    如您所见,MessageListModel是我的格式化模型,而InboxViewModel是包含格式模型的视图模型。

    然后我将整个辣酱玉米饼馅传递给View:

    return View(model);
    

    我的主要问题是,虽然将初始列表限制为仅包含用户是收件人的邮件(这会大大减少返回的数据集)是正确的,但是我应该放置后续过滤器,例如确保发件人是仍然活跃在系统上,进一步向最终的视图模型?例如,我应该从控制器移动.Where()子句的后半部分:

    var UserId = User.Identity.GetUserId();
    var UserRole = User.IsInRole("HEO");
    IEnumerable<Messaging> data = await db.Messaging
      .Where(x => x.MessageTo == UserId) // Much shorter now!
      .OrderByDescending(x => x.MessageSent)
      .ToListAsync();
    InboxViewModel model = new InboxViewModel(data, UserRole);
    

    进入模型?:

    public class InboxViewModel {
      public IEnumerable<MessageListModel> Inbox { get; set; }
      public InboxViewModel() { }
      public InboxViewModel(IEnumerable<Messaging> data, bool UserRole) {
        Inbox = data
          // Second half of .Where() is here:
          .Where(x => (UserRole ? x.MsgSender.RecruiterProfile.ProfileActive : x.MsgSender.HEOProfile.ProfileActive))
          .Select(x => new MessageListModel {
            MessageId = x.MessageId
          , MessageRead = (x.MessageRead != null ? true : false)
          , MessageName = (UserRole ? (x.MsgSender.RecruiterProfile.CompanyName.Length > 16 ? x.MsgSender.RecruiterProfile.CompanyName.Substring(0, 16) + "…" : x.MsgSender.RecruiterProfile.CompanyName) : (x.MsgSender.HEOProfile.UsualName.Length > 32 ? x.MsgSender.HEOProfile.UsualName.Substring(0, 32) + "…" : x.MsgSender.HEOProfile.UsualName))
          , MessageSubject = (x.MessageSubject.Length > 64 ? x.MessageSubject.Substring(0, 64) + "…" : x.MessageSubject)
          , MessageSent = x.MessageSent.ToString("yyyy-MM-dd")
        }).ToList();
      }
    }
    

    我认为.Where()过滤发件人,如果他们的帐户处于活动状态(过滤掉很少的项目)会更有效 数据集之后从数据库中提取(在实际的数据库查询中使用它会使查询速度降低,而不是在提取后完成)。而.Where()的前半部分(将数据集限制为仅供用户使用的那些消息)在控制器中更为重要,因为它大大减少了首先返回的数据集,并且这样可以使整个数据库调用更加高效。

    特别是,将显示的消息限制为发送方在系统上仍处于活动状态的消息在技术上是业务逻辑,而对于专门发送给当前用户的消息的初始DB调用则不是。所以恕我直言,.Where() 的前半部分应该在控制器中,而.Where() 的后半部分应该在模型中。< / p>

    建议?

1 个答案:

答案 0 :(得分:0)

根据我的经验,在speed方面重要的是对数据库的请求次数和数据大小或响应中的记录号。在你的情况下,如果我是你第一个,我会检查用户是否有效。根据您用于身份验证的服务,您通常不需要向数据库发送请求以检查用户是否处于活动状态。然后发送一个带有过滤条件的请求以最小化数据量。还应该认真考虑加载或延迟加载。对于formatting model,我会使用automapper之类的工具,这些工具经过优化并且运行速度更快。最后,我会将数据注释用于.ToString("yyyy-MM-dd")等视图模型目的。