views:

211

answers:

1

Class Customer has the following method, which returns an IQueryable with the linq query to get the active sales for a customer:

    public IQueryable<SalesHeader> QueryCurrentSales()
    {
        // this.SalesHeaders is an association defined in the DBML between
        // the Customer and SalesHeader tables (SalesHeader.CustomerId <-> Customer.Id).
        return this.SalesHeaders
            .Where(sh => sh.Status == 1).AsQueryable();
    }

The idea is to centralise the query definition in a single point, so that later we can get the SalesHeader rows, do a count, paginate using the PaginatedList class (from NerdsDinner), and add further Where conditions when searching Sales within active SalesHeaders.

However, after running the SQL Sever profiler, I've discovered that doing the following, gets all the rows and then does the Count in memory.

    // cust is an object of type Customer.
    int rows = cust.QueryCurrentSales().count();

I guess that the problem lies in the fact that we have used the AsQueryable() method, but I don't know what would be the correct way to accomplish what we intended.

+1  A: 

You haven't shown what SalesHeaders is. The fact that you feel you need to do AsQueryable suggests that it's returning an IEnumerable<T> rather than an IQueryable<T>... which is probably the problem. If you could show SalesHeaders, we may be able to help.

It's possible that instead of using AsQueryable you may be able to just cast to IQueryable<SalesHaeder> if the SalesHeaders property is returning an expression which could actually be returned as IQueryable<SalesHeaders> in the first place - but in that case I'd suggest changing the property type instead.

EDIT: Okay, if it's an entity set then that's probably tricky to fix directly.

I know it's ugly, but how about something like:

public IQueryable<SalesHeader> QueryCurrentSales()
{
    // You *may* be able to get away with this in the query; I'm not sure
    // what LINQ to SQL would do with it.
    int id = this.Id;

    return context.SalesHeaders
                  .Where(sh => sh.Status == 1 && sh.CustomerId == id);
}

Here I'm assuming you have some way of getting to the data context in question - I can't remember offhand whether there's an easy way of doing this in LINQ to SQL, but I'd expect so.

Jon Skeet
I've added a comment to the code in the original post. SalesHeaders is a property that was created automatically when I defined the Association between the Customer and SalesHeader tables in the DBML.Unfortunately, doing a cast didn't work.I've checked into getting the data directly from the context "context.SalesHeaders.Where(...)", but it looks like .Where always returns an IEnumerable :S
salgiza
Disregard the last line from the previous comment. It seems .Where (when accessing the data from the context instead of through the association) can be assigned both to IQueryable and IEnumerable variables. And it creates the final SQL query correctly (yess!)It's a shame, because this.SalesHeaders.Where(...) was a much nicer way to resolve it. Do you know if it would have worked had we used Linq to Entities to access the SQL Server?
salgiza
@salgiza: I don't know whether LINQ to Entities would work any better I'm afraid.
Jon Skeet