从包装的IQueryable中获取最终投影

时间:2014-01-09 02:41:16

标签: c# linq wcf-data-services expression-trees

我不确定如何表达我想要实现的目标,而不会显示一些伪代码 -

假设定义了以下DTO:

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int Age { get; set; }
}

我们定义了两个不同的自定义IQueryable<T>类:

public class InnerQueryable<T> : IQueryable<T>
{
    // ...
}

public class OuterQueryable<T> : IQueryable<T>
{
    public OuterQueryable(IQueryable<T> inner)
    {
        // Assign `inner` to a local variable to be used in `IQueryable<T>` impl.
        // ...
    }

    // ...
}

注意:OuterQueryable<T>旨在通过包装来扩展任何其他IQueryable<T>类型的行为。

一种相当天真的扩展方法,可以简单地创建OuterQueryable<T>实现:

public static IQueryable<T> ToOuterQueryable<T>(this IQueryable<T> inner /*, ... */)
{
    // Assume `OuterQueryable<T>` has a constructor that takes another `IQueryable<T>`.
    return new OuterQueryable<T>(inner /*, ... */);
}

给定如下所示的表达式,InnerQueryable<T>实例是否有任何方法可以在查询被OuterQueryable<T>包装后找出选择了哪些特定属性?

InnerQueryContext.AsQueryable<Person>().Where(p => p.Age > 30)
    .ToOuterQueryable().Select(p => new
    {
        p.FirstName,
        p.LastName
    };

无论如何,InnerQueryable<T>知道构建的查询 OuterQueryable<T>仅返回Person.FirstNamePerson.LastName

如果有助于显示上下文,我有一个返回内部实体的WCF数据服务,但我需要能够知道从服务返回内部实体的哪些特定成员。 WCF DS在这种情况下定义了OuterContext<T>,我还没有找到一种方法来拦截投影后的响应,告诉我我在寻找什么。

欢迎任何想法。


更新:什么是InnerQueryable<T>OuterQueryable<T>

如果您不熟悉WCF数据服务的体系结构,那么答案是相当复杂的,但是在这里:

在WCF数据服务中,服务将IQueryable<T>属性公开给DataServiceProvider实现(即EntityFrameworkDataServiceProviderReflectionDataServiceProvider或实现必要接口的自定义DataServiceProvider实现(或多个))。

这些核心IQueryable<T>属性充当通过服务公开的资源的基础,并且构建在使用LINQ查询的可组合性质的基础上。使用上面的Person实体的简单示例如下所示:

public class SimpleContext
{
    public IQueryable<Person> People
    {
        get
        {
            return new[] {
                new Person { FirstName = "George", LastName = "Jetson", Age = 43 },
                new Person { FirstName = "Elroy", LastName = "Jetson", Age = 7 }
            }.AsQueryable();
        }
    }
}

这个SimpleContext将由简单的数据服务实现引用:

public class SimpleDataService : DataService<SimpleContext>
{
    // InitializeService method and others...
}

现在,当我查询传递投影的数据服务时:

http://localhost/SimpleDataService/People()?$select=FirstName,LastName

该框架将从IQueryable<Person>返回SimpleDataContext.People并将其传递给内部IQueryProvider / IQueryable实现,该实现了解如何从查询字符串生成表达式树参数,然后使用IQueryable<Person>作为其来源撰写另一个查询。

从概念上讲,我上面的原始问题描述了如何复制行为,而不必担心所有WCF数据服务的内容。

1 个答案:

答案 0 :(得分:2)

我仍然不太明白为什么WCF DS需要OuterQueryable。它需要做的是解析查询,然后根据它调用InnerQueryable

如果你的InnerQueryable周围确实存在某种包装,那么完全由该包装器来决定你的包装器可查询的内容。

考虑包装器的两个简单实现:如果包装器只是将每个方法调用转发给包装对象,那么您将能够直接看到所有内容。另一方面,如果包装器根本不做任何事情,那么根本无法观察任何事情。