如何在IEnumerable/IQueryable集合上应用odata FilterClause

本文关键字:应用 odata FilterClause 集合 IQueryable IEnumerable | 更新日期: 2023-09-27 18:25:23

我正在为我们的odata v4服务实现一些功能。我们希望支持所有函数的filter查询选项,就像实体集合一样。

假设我们有一个SearchProducts函数,它接受ProductType参数,并返回属于特定ProductType的所有产品。

现在的问题是,我没有找到任何支持这种需求的odata内置方法。我唯一能弄清楚的方法是手动解析FilterClause,然后将其应用于函数返回的结果。

检查此示例代码:

IQueryable<Product> collection = _service.SearchProducts(ProductType.Phone); 
var parser = new ODataUriParser(model, new Uri("SearchProducts(ProductType='Phone')?$filter=Name eq 'IPhone'", UriKind.Relative));
var filter = parser.ParseFilter();
// TODO: apply filter on collection, to filter all iphones. get the results same as the following code 
// TODO: collection = collection.Where(p=>p.Name == "IPhone");

集合将是所有Phone产品。添加$filter字符串后,它应该返回所有IPhone产品。

我可以将FilterClause解析为lambda表达式,然后将其应用于集合以返回正确的结果。但考虑到$filter的复杂性,解析器可能非常复杂,并且会花费大量时间。

有人能快速解决这个问题吗?感谢

如何在IEnumerable/IQueryable集合上应用odata FilterClause

真正的问题是:如何在没有整个OData的asp基础设施的情况下使用OData查询语言进行过滤?这可以通过提取$filter并将其应用于IQuerable数据库上下文来完成。搜索也是如此。通过这种方式,我们有了更多的灵活性,但可以重用OData-sql生成代码和解析逻辑。

首先,在DI中注册这个model,这样你就可以在任何地方注入它:

ODataModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<Order>("Orders");
var model = builder.GetEdmModel();

然后,在您的控制器中接受过滤器参数作为字符串参数:

IActionResult Get(string filterParam) 
{
   // test query
   filterParam = "(MyCount ne 10) and (EnumField in ('1', '2')) and (Address/Id eq 1)";

稍后构建类似的东西。你可以在这里放置其他东西,比如$search,$top,$count:

Dictionary<string, string> options = new Dictionary<string, string>
{
  {"$filter", filterParam },
};

解析查询:

IEdmType type = model.FindDeclaredType("MyEntities.Order");
IEdmNavigationSource source = model.FindDeclaredEntitySet("Orders");
ODataQueryOptionParser parser = new ODataQueryOptionParser(model, type, source, options);

将其应用于DB上下文的集合。IQuerable将包含生成的SQL,以缩小结果的范围。

var context = new ODataQueryContext(model, typeof(Order), null);
var opts = new ODataQueryOptions<Order>(context, this.Request);
FilterQueryOption filterQuery = new FilterQueryOption(" ", context, parser);
 
var iQuerableResult = filterQuery.ApplyTo(_dbSet_dbContext, new ODataQuerySettings { });

请记住,这是一个原始的PoC代码。不是生产准备好的东西。