Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

I expose an IQueryable method from my business 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.

like image 248
Jason Wicker Avatar asked Nov 05 '22 17:11

Jason Wicker


1 Answers

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.

like image 66
smaclell Avatar answered Nov 15 '22 03:11

smaclell