views:

598

answers:

2

I'm trying to create an html table for order logs for customers. A customer is defined as (I've left out a lot of stuff):

public class Customer
{
    public LazyList<Order> Orders { get; set; }
}

The LazyList is set when fetching a Customer:

public Customer GetCustomer(int custID)
{
    Customer c = ...
    c.Orders = new LazyList<Order>(_repository.GetOrders().ByOrderID(custID));
    return c;
}

The order log model:

public class OrderLogTableModel
{
    public OrderLogTableModel(LazyList<Order> orders)
    {
        Orders = orders;
        Page = 0;
        PageSize = 25;
    }

    public LazyList<Order> Orders { get; set; }
    public int Page { get; set; }
    public int PageSize { get; set; }
}

and I pass in the customer.Orders after loading a customer. Now the log i'm trying to make, looks something like:

<table>
<tbody>
<% 
    int rowCount = ViewData.Model.Orders.Count();
    int innerRows = rowCount - (ViewData.Model.Page * ViewData.Model.PageSize);
    foreach (Order order in ViewData.Model.Orders.OrderByDescending(x => x.StartDateTime)
                            .Take(innerRows).OrderBy(x => x.StartDateTime)
                            .Take(ViewData.Model.PageSize))
    {
        %>
        <tr>
            <td>
                <%= order.ID %>
            </td>
        </tr>
        <%
    }
%>
</tbody>
</table>

Which works fine. But the problem is evaluating ViewData.Model.Orders.Count() literally takes about 10 minutes.

I've tried with the ViewData.Model.Orders.Count property instead, and the results are the same - takes forever.

I've also tried calling _repository.GetOrders().ByCustomerID(custID).Count() directly from the view and that executes perfectly within a few ms.

Can anybody see any reason why using the LazyList to get a simple count would take so long? It seems like its trying to iterate through the list when getting a simple count.

+3  A: 

LazyList loads all data on first use, so you are loading all the orders in list on the Count call. Getting all data from db, instantiating objects, etc. When you call _repository.GetOrders().ByCustomerID(custID).Count(), it just counts the rows in database and returns one number.

Alex Reitbort
A: 

The problem you've got is that the LazyList<T> is populating the entire list of orders from the database, just so you can count them. That's a lot of work just to get a simple count.

You could modify the Count method on the LazyList<T> class to the following:

public int Count 
{
    get 
    { 
        if(inner == null)
            return query.Count;
        else
            return inner.Count;
    }
}

If the list of orders hasn't been hydrated yet it will instead ask the IQueryable for the Count. By calling .Count() on the IQueryable you are asking LINQ to SQL to just get the number of results, this will get translated to something like "SELECT COUNT(*) FROM Orders". Doing this is much more efficient than hydrating all of the results and then counting them, especially if you're only interested in the number!

DoctaJonez