views:

63

answers:

4

I've been coding with 'using' blocks but I am wondering if I can return an IQueryable from the following without the object being disposed before I access it.

public IQueryable<Contact> GetContacts(string clientID)
{
    using (dbDataContext db = new dbDataContext())
    {
        var contacts = from _contacts in db.Contacts
                        where _contacts.ClientID == clientID
                        orderby _contacts.LastName ascending
                        select _contacts;

        return contacts;
    }
}

Do I simply remove the 'using' block and let .Net manage the objects, or can I get Linq to run the query early and return the populated object.

+2  A: 

If you don't expect to further compose the data (at the db-server), then:

return contacts.ToList().AsQueryable();

although in that case I'd prefer to return IEnumerable<Contact> or IList<Contact> to make the non-composable nature obvious. With the AsQueryable approach, it'll still be composable, but it'll compose via LINQ-to-Objects (so after it has fetched the records from the database).

If you do expect to further compose it, then you should pass the data-context (or, if possible, an upstream IQueryable<something>) into the method, and let the caller handle the lifetime:

public IQueryable<Contact> GetContacts(dbDataContext db, string clientID)
{
    return from _contacts in db.Contacts
           where _contacts.ClientID == clientID
           orderby _contacts.LastName ascending
           select _contacts;
}
Marc Gravell
Good answer. Thanks. Which is more lightweight IEnumerable or IList in terms of memory usage and performance?
polom1nt
@IckleMonkey - it is the *concrete* type that matters most there, but one obvious advantage of `IList<T>` is that it will expose `.Count` etc (and an indexer), making access more convenient. But regardless of `IList<T>` vs `IEnumerable<T>`, it still *is* a `List<T>`, so memory usage is independent. Or for a more concise answer: use `IList<T>`
Marc Gravell
Perfect. Thanks very much.
polom1nt
A: 

you could do something like this

public IQueryable<Contact> GetContacts(string clientID)
{
    IQueryable contacts;
    using (dbDataContext db = new dbDataContext())
    {
        contacts = from _contacts in db.Contacts
                        where _contacts.ClientID == clientID
                        orderby _contacts.LastName ascending
                        select _contacts;


    }

    return contacts;
}
PaulStack
That won't help - deferred execution of LINQ queries means that the db-context is still disposed long before `GetEnumerator()` is called on the underlying query. So no workee.
Marc Gravell
A: 

Hi IckleMonkey,

Can you make the context object a member instance of your class? If you can you'll defer the call to run the query until you actually touch the enumerator underlying the IQueryable instance you're returning. It depends on what you want to do. Do you need to return IQueryable from this method, or can you make do with IEnumerable ?

Øyvind
I think I will go with the IEnumerable, if I use the member instance method, then I may run into the same problem if my class is used as a 'using' block, and I want access to the returned data outside of this. Thanks for the suggestion.
polom1nt
A: 

The contact object instance in IQueryable result set will retain the reference of datacontext used within the using block and will work in the client code much as expected. You will be able to perform deferred SQL operations on the resultant IQueryable instance and do other IQueryable operationas normally.

this. __curious_geek
When I try, I get 'DataContext accessed after Dispose'.
polom1nt