在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”)?
答案 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()”方法调用之前。
不容易,但很可能