实现服务可查询:IQueryable到IEnumerable并返回

时间:2014-01-16 18:56:49

标签: linq wcf entity-framework linq-to-entities wcf-ria-services

在RIA Services(以及可能的其他框架,如WCF数据服务)中,可以通过提供返回IQuerably的方法来实现数据服务方法。例如:

IQueryable<Customer> GetCustomers()
{
    return this.DbContext.Customers.Where(c => !c.IsDeleted);
}

来自客户端的查询可以提供额外的过滤器(以及其他内容)。客户端提供的过滤器和仅返回未删除的客户的过滤器将被合并,并通过实体框架(或使用任何ORM)在SQL中发送到数据库。

实体框架通常不足以表达想要编写的查询,在这种情况下我们必须转到linq对象:

IQueryable<CustomerWithFluff> GetCustomers()
{
    var customers =
        this.DbContext.Customers
        .Include("FluffBits")
        .Where(c => !c.IsDeleted)
        .ToList();

    return
        from c in customers
        select new CustomerWithFluff()
        {
            CustomerName = c.Name,
            ComplexFluff = String.Join(", ", from b in c.FluffBits select b.FluffText)
        };
}

数据库的sql现在仍然包含对“IsDeleted”的限制,但不包含客户端提供的任何进一步过滤器:在已经获取所有数据后,这些过滤器将应用于linq到对象级别。

如果我不想让客户端过滤我需要用linq-to-objects组成的任何数据(本例中只有“ComplexFluff”),有没有办法继续过滤简单投影的属性(在本例中仅为“CustomerName”)?

1 个答案:

答案 0 :(得分:1)

是的,但并不像人们所期望的那么简单。你必须覆盖

public override IEnumerable Query(QueryDescription queryDescription, out IEnumerable<ValidationResult> validationErrors, out int totalCount)

方法,您可以在queryDescription.Query中获取将针对您的Queryable执行的实际查询和表达式(即queryDescription.Method.Invoke返回的内容(this,queryDescription.ParamterValues))

然后,您可以获取客户端发送的表达式并将其传递给您的方法(可能作为对domainService中某种字段的引用,不要忘记在每次调用时都会实例化WCF Ria服务,即常规的wcf perCall实例化模型)你必须要结合

var customers =
        this.DbContext.Customers
        .Include("FluffBits")
        .Where(c => !c.IsDeleted)

在“ToList()”方法调用之前。

不容易,但很可能