This project has moved and is read-only. For the latest updates, please go here.

Dynamic Remote Query

Remote Linq allows to create complex linq queries and send them to a remote service to be applied and executed against arbitrary enumerable or queryable data sources.

The Client

Build the client in two simple steps:

  1. Create a RemoteRepository class exposing collection properties of type IQueryable<T> which you create using RemoteQueryable.Create<T>() method
  2. Write and use a linq expression based on the queryable collections exposed by yor RemoteRepository class 
namespace Client
{
  class Program
  {
    async Task RunAsync()
    {
      var repo = new RemoteRepository("net.tcp://server/1234/queryservice");
 
      var query =
        from c in repo.ProductCategories
        join p in repo.Products
          on c.Id equals p.ProductCategoryId
        join i in repo.OrderItems
          on p.Id equals i.ProductId
        group new { c, p, i } by c.Name into g
        where g.Sum(x => x.i.Quantity) >= 5
        select new
        {
          Category = g.Key,
          Total = new
          {
            Quantity = g.Sum(x => x.i.Quantity),
            Amount = g.Sum(x => x.i.Quantity * x.p.Price)
          },
        };
 
      var result = await query.ToListAsync();
    }
  }
 
  class RemoteRepository
  {
    private readonly Func<ExpressionTask<IEnumerable<DynamicObject>>> _dataProvider;
 
    public RemoteRepository(string uri)
    {
      _dataProvider = async expression =>
      {
        using (var proxy = new ServiceProxy(uri))
        { 
          var result = proxy.ExecuteQueryAsync(expression);
          return await result;
        }
      };
    }
 
    public IQueryable<ProductCategory> ProductCategories
    {
      get { return RemoteQueryable.Create<ProductCategory>(_dataProvider); }
    }
    public IQueryable<Product> Products
    {
      get { return RemoteQueryable.Create<Product>(_dataProvider); }
    }
    public IQueryable<OrderItem> OrderItems
    {
      get { return RemoteQueryable.Create<OrderItem>(_dataProvider); }
    }
  }
}

The Service

Building the server is even easier:

  1. The service method takes a remote linq expression as a parameter
  2. Call the extension method Execute on the query parameter
  3. Pass a delegate to the Execute method mapping from Type to IQueryable collections
  4. Return the result - don't worry, the dynamic objects are converted to the strongly typed result on client-side automatically by the framework
namespace Server
{
  class QueryService
  {
    public IEnumerable<DynamicObject> ExecuteQuery(Expression query)
    {
      var dataContext = new EFContext();
      var result = query.Execute(queryableProvider: type => dataContext.Set(type));
      return result;
    }
  }
}

 

Last edited Sep 11, 2014 at 9:44 PM by ChristofSenn, version 11