3

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

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

    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)

EventServiceIQueryable 进行简单查询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 to 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 屏幕截图

4

2 回答 2

1

您基本上有两个选项可以避免使用 LINQ to SQL 选择 n+1:

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

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

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

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

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

您可以让查询准确返回特定 ViewModel 类中所需的内容,而不是选择事件列表然后使用该实体的属性 Comments 和 Locations。然后 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;
}
于 2012-01-30T11:29:52.690 回答
0

你会想要.Include("Locations").Include("Comments")在各自的查询中。我相信它先于.Where(),但我对此并不积极。

于 2012-01-26T18:29:12.340 回答