我已将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
修改 - 添加了屏幕截图
答案 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()
之前,但我对此并不乐观。