开发者

Is there any way to delay- execute a delegate against an IQueryable<T> after/during execution?

I expose an IQueryable method from my b开发者_JAVA百科usiness layer for use in other layers. I would like to execute a function against each of the items in the enumeration, once the query has executed down-level.

It seems like there should be an event that is raised after the query executes, so that I can then operate on the results from this common layer.

Something like:

public IQueryable<User> Query() 
{
    return _Repository.Query<User>().ForEachDelayed(u=> AppendData(u));
}

I want the ForEachDelayed function to return the IQueryable without executing the query. The idea is, once the query is executed, the results are passed through this delegate.

Is there something like this out there? If not, is there an event like "IQueryable.OnExecute" that I can subscribe to?

Any help would be awesome -- thanks!

EDIT:

I thought I had the answer with this:

var users = from u in _Repository.Query<User>()
            select AppendData(u);
return users;

But now, I get the following error:

Method 'AppendData(User)' has no supported translation to SQL.

I really need a delegate to run AFTER the query has executed.


The Easy Way

Another option that is much simpler would be to append what you need using an Iterator, see the example below. The downside of this approach is that everything would have been pulled into memory while the iteration is performed so that AppendData is only executed on the returned data. This is similar to the option by @Chris but you are not forced to create a new Func and Select query every time you want to use the method.

static void Main(string[] args)
{
    var data = new List<int> { 1, 2, 3, 4, 5 }.AsQueryable().AppendData();

    Console.WriteLine("Before execute");

    Console.Write("{ ");
    foreach (var x in data)
       Console.Write("{0}, ", x);

    Console.WriteLine( "}");

    Console.WriteLine("After execute");

    Console.Read();
}

// Append extra data. From this point on everything is in memory
// This should be generic, i.e. AppendData<T>, but I an easy way to "append"
static IEnumerable<int> AppendData(this IEnumerable<int> data)
{
    Console.WriteLine("Adding");
    foreach (var x in data)            
        yield return x * 2;
}

The Hard Way

I do not believe there are any built in events like this but you could probably add your own by implementing your own IQueryable wrapper.

Here is a series on writing a complete IQueryable provider which will also show you where you could fit your wrapper, most likely around that IQueryProvider.

Good luck and Hope this helps.


Have you had a look at ToExpandable()?

http://tomasp.net/blog/linq-expand.aspx

You could always call ToList() before executing your code - that will invoke the SQL, then you can run your code on the result set -

var users = from u in _Repository.Query<User>().ToList();

//this will invoke AppendData() for each u
var retVal = from u in users
            select AppendData(u);

return retVal;


Right now you are using some ORM, correct? I'm pretty sure you can achieve this using the lambda expression form by explicitly using the IEnumerable version of select, instead of IQueryable.

var users = (_Repository.Query<User>() as IEnumerable<User>).Select(u => AppendDate(u)); 
return users; 

When the query is actually executed it will fetch all of the data returned by Query() and then do the select in memory.


I haven't tried but I think you could use automapper to map to a different or similar object returning IQuerible and use "AfterMap" on the mapping to execute your code after the query is done.

0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜