views:

223

answers:

3

For my application I want to be able (if possible) to execute a LINQ to SQL query outside of it's context.

The reason this would be nice for me is that I would store the IQueryable in objects in the cache. When I later need them they would be executed and the cached object would be updated with the items from the query.

The reason I want to be able to do this unorthodox thing is because of how the CMS I use is built.

Have anyone done anything like this before?

Edit, Further Explanation: In the CMS I work with (EPiServer) I have built and attached a Custom Page Provider. Which lets me make Pages of any datasource. In it I am responsible with creating PageData for the CMS. The PageData consists of Properties which I also populate in my Provider.

My method that builds PageData gets called when it does a listing aswell as getting a specific page. When it does a listing it uses only a small amount of the properties needed in the PageData so I'd like to instead of setting a result set to a property, I'd like to set an query. In that way, the queries to the database will only be executed when needed.

The PageData object is after my creation Cached. But when it's not cached I don't want to make 7 queries against the database for just a listing.

A: 

Is this for performance purposes?

Caching the results of LINQ queries
http://petemontgomery.wordpress.com/2008/08/07/caching-the-results-of-linq-queries/

Robert Harvey
Yes it is because of performance and the reason I want to do it that way is because of how the CMS works.The short explanation it wants me to build its Page-Object in a function that is used both for listing pages and viewing the specific page. Since I build it from alot of tables, I want to be able to store just an IQuerable that would be executed when it's needed.
ullmark
The Page-Object is automaticly cached by the object so if i just could get an query from linq to sql to be able to be executed outside it's context it would work out really nicely.
ullmark
@ullmark - The cost is not in defining the IQueryable, the cost is in executing it (having the expression tree translated into T-SQL, sending that [over the wire] to the database, having the database execute the query, returning the results, and materializing the results). In other words, caching the query itself will not save you anything performance-wise. But caching the data/results will...
KristoferA - Huagati.com
@KristoferA, yes I know. It was really dumb of me to brought cache up because it really has nothing to do with what i want to do. I'll edit and try to explain better
ullmark
A: 

Would this work?

var myIQueryableObject = (query).ToList().AsQueryable();
Robert Harvey
Wouldn't that execute the query directly when i build it? The ToList() makes it execute right?
ullmark
Yes it does, but I though that's what you wanted to do: break the result off so you could query it outside of the DataContext.
Robert Harvey
A: 

Do you mean you want to attach a query (an IQueryable) to a new datacontext instance? Or a completely different datacontext?

If so, you could take the query, replace all references to the DC instance in the query's expression tree (query.expression) using something like this:
http://huagati.blogspot.com/2009/10/code-sample-search-and-replace-in-linq.html

...and then create a new query using IQueryProvider.CreateQuery. For the last step you can get hold of the IQueryProvider from a 'dummy query' against the new DC, e.g.:

IQueryable<Foo> dummyQuery = dc.Foos;
IQueryProvider prov = dummyQuery.Provider;


Update:

After the clarification of the question, I think what you're maybe looking for is having your queries wrapped in iterator functions.

E.g.:

public IEnumerable<SomeEntity> SomeEntityQuery()
{
    //run the query
    List<SomeEntity> result = null;
    using (SomeDataContext dc = new SomeDataContext())
    {
        result = (from se in dc.SomeEntity where ... select se).ToList();
    }

    //and return the query results
    foreach (SomeEntity se in result)
    {
        yield return se;
    }
}

...and then:

//the query will not run when this assignment takes place...
IEnumerable<SomeEntity> someEntityList = SomeEntityQuery();

//but when we start enumerating the results, the SomeEntityQuery method
// will execute the query and then begin returning the results...
foreach (SomeEntity se in someEntityList)
{

}
KristoferA - Huagati.com
Hmm, I will give this a try! I'll get back with the result. Thanks!
ullmark
As I thought; that doesn't work because: "Cannot access a disposed object. Object name: 'DataContext accessed after Dispose.'."
ullmark
Strange - the code sample above works here. Are you accessing any navigation properties on the entities, in addition to scalar properties?
KristoferA - Huagati.com
Accually I am selecting the query into a container class. With just three string properties, so no navigationproperties is availible.
ullmark
Tried it with selecting the entity and just enumerating it afterwards, just like in your example. Same error. My code -> http://pastie.org/661728
ullmark
Ok, maybe try switching to a list for the internal list of objects... (updated above)
KristoferA - Huagati.com
But ToList would execute the query so that will not work. I have come up with a solution (not yet implemented) and that is making my DataContext as a Singleton Instance. I don't need object tracking here so i don't think that would have any disadvantages. And the context would always exist so it won't be distposed...
ullmark
No, that is the funny tihng with iterators. It won't execute the code inside the iterator function until you start enumerating the contents. Although it is just a method in code, the compiler will do all kinds of fancy stuff where it gets wrapped in its' own class etc.
KristoferA - Huagati.com