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

发布于 2024-11-02 04:06:06 字数 353 浏览 2 评论 0原文

在我的 RIA 域服务中,我公开了一个

IQueryable<客户>

在客户端我可以这样查询

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

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

RIA 或 EF 是否公开了任何“钩子”,以便在 EF 解析表达式并将 sql 发送到数据库之前检查/操作表达式? 任何有关 RIA 如何在后台工作的 url 也将不胜感激。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

小红帽 2024-11-09 04:06:06

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

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

关于能够查看表达式树,您可以创建 IQueryable 和 IQueryProvider 接口的存根实现,并使用它来查看表达式树(用于调试)。下面是实现这些接口的代码示例(从 IQueryProvider 中删除了重要器官,大量借用自 任性的博客 - 构建 IQueryable 提供程序):

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
}

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
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文