何时/如何将RIA服务查询添加到EF表达式树?

时间:2011-04-18 07:06:56

标签: silverlight entity-framework ria wcf-ria-services

在我的RIA域名服务中,我暴露了一个

  

的IQueryable<顾客>

在客户端上我可以像

一样查询
  

DomainContext.Customers.Where(c =>   c.Id == theID)

我的问题是如何将此表达式添加到发送到数据库的查询中,因为我的域服务方法不会使用IQueryable。

在EF解析它并将sql发送到数据库之前,RIA或EF是否有任何“钩子”暴露以检查/操纵表达式? 任何关于RIA如何在引擎盖下工作的网址也会受到赞赏。

1 个答案:

答案 0 :(得分:2)

我实际上遇到了你的帖子,因为我正在寻找完全相同的信息。我正在编写一个简单的MySql查询提供程序,用于RIA服务。由于没有答案,我认为即使问题有点陈旧,我也会添加我的发现。当您编写服务器端查询方法时,它可能是“IQueryable GetCustomers()”,但在客户端,您将拥有GetCustomersQuery()。实际获取数据的方式不是通过调用GetCustomers方法,而是通过调用Load方法并将查询传递给它。

关键是RIA将使用您的GetCustomers方法获取IQueryable,从客户端组合查询中获取表达式树并将它们组合在一起,然后才枚举IQueryable并返回结果。这就是查询提供程序可以看到您在客户端创建的表达式树的原因。有一种方法可以查看实体框架生成的SQL查询字符串,但我不确定如何(尝试查找ToTraceString方法)。

关于能够查看表达式树,您可以创建IQueryable和IQueryProvider接口的存根实现,并使用它来查看表达式树(用于调试)。这是一个用于实现这些接口的代码示例(从IQueryProvider中删除重要器官,大量借鉴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
}