开发者

How to track down Duplicate Linq to SQL Queries identified by MiniProfiler?

开发者 https://www.devze.com 2023-04-10 02:34 出处:网络
I\'ve wired up the MvcMiniProfiler to my app, and it\'s reporting Duplicate Queries. I\'ve set a BreakPoint in my Repository

I've wired up the MvcMiniProfiler to my app, and it's reporting Duplicate Queries.

I've set a BreakPoint in my Repository

    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

And I've hit the page in question.

My code hits the Read() function twice through my service layer (this is by design since I can't figure out how to reduce the calls)

        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)

The EventService does a simple query against the 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

Unfortunately I can't figure out why MiniProfiler is saying there are 8 Duplicate queries (13 in total).

Revised

So it appears as though Sam has stated that I'm not pre-loading my relationships within my queries.

How do I appropriately pre-load relationships in Linq to SQL? Can anyone lend any advice?

Edit

Here's the ViewModel that's being created.

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)开发者_StackOverflow)
            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

Edit - added screenshot

How to track down Duplicate Linq to SQL Queries identified by MiniProfiler?


You basically have two options to avoid SELECT n+1 with LINQ to SQL:

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

DataLoadOptions enables you to specify per entity exactly that related tables should be eager-loaded. In your case, for the entity Event, you could specify LoadWith for both Comments and Locations. Whenever you load Events, Comments and Locations will then be preloaded.

The DataLoadOptions is a property you can set on the DataContext itself.

2) Use projection to fetch all the data you need in one specific query, instead of relying on lazy loading the related entities.

You have imposed a repository on top of your DataContext, so this might not be the approach you want to take, but:

Instead of selecting a list of Events and then using this entity's properties Comments and Locations, you could have your query return exactly what you need in a specific ViewModel class. LINQ to SQL would then fetch everything in a single SQL query.

I consider this the best approach if you don't absolutely NEED to abstract away the DataContext behind a repository interface. Even if you do, you could consider having the repository return View specific results, i.e.

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

with EventViewModel being

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


you're going to want to .Include("Locations") and .Include("Comments") in the respective queries. I believe it goes before the .Where(), but I'm not positive about that.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号