如何跟踪MiniProfiler识别的Duplicate Linq到SQL查询?

时间:2011-10-03 19:46:14

标签: asp.net-mvc-3 linq-to-sql profiling mvc-mini-profiler

我已将MvcMiniProfiler连接到我的应用程序,并报告重复查询。

我在我的存储库中设置了一个BreakPoint

    Public Function Read() As System.Linq.IQueryable(Of [Event]) Implements IEventRepository.Read
        Dim events = (From e In dc.Events
                      Select e)
        Return events.AsQueryable ''# BREAKPOINT HERE
    End Function

我点击了相关页面。

我的代码通过我的服务层点击Read()函数两次(这是设计,因为我无法弄清楚如何减少调用)

        Dim eventcount = EventService.GetHotEventCount() ''# First Hit
        Dim eventlist = EventService.GetHotEvents((page - 1) * 5) ''# Second Hit
        Dim model As EventsIndexViewModel = New EventsIndexViewModel(eventlist, page, eventcount)

        Return View("Index", model)

EventService针对IQueryable Read

进行简单查询
    Public Function GetHotEvents(ByVal skip As Integer) As List(Of Domain.Event) Implements IEventService.GetHotEvents

        Return _EventRepository.Read() _
            .Where(Function(e) e.EventDate >= Date.Today AndAlso
                               e.Region.Name = RegionName) _
            .OrderByDescending(Function(e) (((e.TotalVotes) * 2) + e.Comments.Count)) _
            .ThenBy(Function(e) e.EventDate) _
            .Skip(skip) _
            .Take(5) _
            .ToList()
    End Function

不幸的是我无法弄清楚为什么MiniProfiler说有8个重复查询(总共13个)。


所以看起来好像Sam已经声明我在我的查询中没有预先加载我的关系。

如何在Linq中适当地预加载关系到SQL?任何人都可以提出任何建议吗?

修改
这是正在创建的ViewModel。

Public Class EventsIndexViewModel
    Public Property Events As List(Of Domain.ViewModels.EventPreviewViewModel)
    Public Property PageNumber As Integer
    Public Property TotalEvents As Integer
    Public Property MapEventsList As List(Of Domain.Pocos.MapPin)
    Public Property JsonMapEventsList As String

    Sub New()
    End Sub

    Sub New(ByVal eventlist As List(Of Domain.Event), ByVal page As Integer, ByVal eventcount As Integer)

        _PageNumber = page
        __TotalEvents = eventcount

        Dim mel As New List(Of MapPin)
        _Events = New List(Of Domain.ViewModels.EventPreviewViewModel)
        For Each e In eventlist
            _Events.Add(New Domain.ViewModels.EventPreviewViewModel(e))
            mel.Add(New MapPin(e.Location.Latitude, e.Location.Longitude, e.Title, e.Location.Name, e.Location.Address))
        Next

        _MapEventsList = mel
        _JsonMapEventsList = (New JavaScriptSerializer()).Serialize(mel)

    End Sub
End Class

修改 - 添加了屏幕截图

miniProfiler Screen Shot

2 个答案:

答案 0 :(得分:1)

你基本上有两个选项来避免使用LINQ to SQL的SELECT n + 1:

1)使用DataLoadOptions - http://msdn.microsoft.com/en-us/library/system.data.linq.dataloadoptions.loadwith.aspx

DataLoadOptions使您能够准确地指定每个实体应该急切加载相关表。在您的情况下,对于实体事件,您可以为注释和位置指定LoadWith。无论何时加载事件,都会预先加载注释和位置。

DataLoadOptions是您可以在DataContext上设置的属性。

2)使用投影来获取一个特定查询中所需的所有数据,而不是依赖于延迟加载相关实体。

您已在DataContext上强加了一个存储库,因此这可能不是您想要采用的方法,但是:

您可以让查询返回您在特定ViewModel类中所需的内容,而不是选择事件列表然后使用此实体的属性“注释和位置”。然后,LINQ to SQL将在单个SQL查询中获取所有内容。

如果你绝对不需要抽象出存储库接口背后的DataContext,我认为这是最好的方法。即使您这样做,也可以考虑让存储库返回查看特定结果,即

dc.Events
    .Where(something)
    .Skip(something)
    .Select(event => new EventViewModel 
        {
            Event = event
            Locations = event.Locations,
            Comments = event.Comments
        }
    );
使用EventViewModel

public class EventViewModel 
{
    Event Event;
    List<Location> Locations;
    List<Comment> Comments;
}

答案 1 :(得分:0)

您希望在相应的查询中.Include("Locations").Include("Comments")。我相信它在.Where()之前,但我对此并不乐观。