Within my RIA domain service I am exposing an
IQueryable< Customer>
and on the client I can query this like
DomainContext.Customers.Where(c => c.Id == theID)
My question is how is this expression getting added to the query that is sent to the database, as my domain service method doesn't take an IQueryable.
开发者_开发问答Are there any 'hooks' exposed by either RIA or EF in order to inspect/manipulate the expression before EF parses it and the sql gets sent to the database? Any url's to how RIA works under the hood would also be appreciated.
I actually came across your post because I was looking for the exact same information. I am writing a simple MySql query provider to be used with RIA services. Since there was no answer I thought I would add my findings even though the question is somewhat old. When you write your server side query method it might be "IQueryable GetCustomers()", but on the client side you will have a GetCustomersQuery(). The way you actually get the data isn't by calling the GetCustomers method, but by calling the Load method and passing it the query.
The point is that RIA will then use your GetCustomers method to get an IQueryable, take the expression tree from your client side composed query and compose them together, and only then does it enumerate the IQueryable and return the result. That is why the query provider can see the expression tree that you created on the client side. There is a way to look at the SQL query string generated by entity framework, but I am not sure offhand how (try looking up the ToTraceString method).
About being able to look at the expression tree, you could create a stub implementation of the IQueryable and IQueryProvider interfaces, and use it to look at the expression tree (for debugging). Here is a code sample for implementing these interfaces (with the vital organs removed from IQueryProvider, borrowed heavily from The Wayward Weblog - Building an IQueryable Provider):
public class Query<T> : IQueryable<T>, IQueryable, IEnumerable<T>, IEnumerable, IOrderedQueryable<T>, IOrderedQueryable
{
IQueryProvider provider;
Expression expression;
public Query(IQueryProvider provider)
{
if (provider == null)
{
throw new ArgumentNullException("provider");
}
this.provider = provider;
this.expression = Expression.Constant(this);
}
public Query(IQueryProvider provider, Expression expression)
{
if (provider == null)
{
throw new ArgumentNullException("provider");
}
if (expression == null)
{
throw new ArgumentNullException("expression");
}
if (!typeof(IQueryable<T>).IsAssignableFrom(expression.Type))
{
throw new ArgumentOutOfRangeException("expression");
}
this.provider = provider;
this.expression = expression;
}
Expression IQueryable.Expression
{
get { return this.expression; }
}
Type IQueryable.ElementType
{
get { return typeof(T); }
}
IQueryProvider IQueryable.Provider
{
get { return this.provider; }
}
public IEnumerator<T> GetEnumerator()
{
return ((IEnumerable<T>)this.provider.Execute(this.expression)).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable)this.provider.Execute(this.expression)).GetEnumerator();
}
}
public class QueryProvider : IQueryProvider
{
#region IQueryProvider Implementation
public IQueryable<T> CreateQuery<T>(Expression expression)
{
return new Query<T>(this, expression);
}
public IQueryable CreateQuery(Expression expression)
{
Type elementType = TypeSystem.GetElementType(expression.Type);
try
{
return (IQueryable)Activator.CreateInstance(typeof(Query<>).MakeGenericType(elementType), new object[] { this, expression });
}
catch (TargetInvocationException e)
{
throw e.InnerException;
}
}
public S Execute<S>(Expression expression)
{
return (S)this.Execute(expression);
}
public object Execute(Expression expression)
{
// You can write code here to look at the expression tree :P
return null;
}
#endregion
}
精彩评论