前言

EF Core 可以把 expression 转换成 string, 但没办法转回来.

想把 string 转成 expression, 目前最合适的工具是 OData. 虽然 Dynamic LINQ 也有人用, 但毕竟 OData 是微软的, 而且有规范文档.

可惜, 就目前的 OData 要想做到 string to expression 还是很麻烦的. 这也是 OData.NxT 想达到的其中一个目标. 但以 OData Team 的实力, 估计还要等好多年呢. 我们还是实际一点, 来看看目前该怎么弄吧.

主要参考:

OData Nxt 004: Query to Expression (IQueryable)

Using Uri Parser

分析源码之路

如果你只是想看结果, 可以跳过这个 part, 如果想学习怎样通过源码找方案可以看看.

OData 肯定是有办法做到的, 在 ODataController 里, 可以通过 ODataQueryOptions.ApplyTo 来把 query params apply 进去 queryable.

猜测它内部就是把 string 转成 expression 然后调用 queryable.where(expression), 大概是这样.

但我们要怎样从 0 搞起呢? 怎么弄 OdataQueryOptions 出来呢?

接着查下去.

打开 ODataQueryOptions.cs

发现要初始化它就需要有一个 HttpRequest...这个接口太上层了吧, 和 HttpRequest 绑的这么死...

接着查下去

在 ApplyTo 方法里看到了 handle $filter 的 apply. 我这里只 focus $filter 的处理 (因为我这一次也只需要到这个).

底层调用的是 FilterQueryOption.ApplyTo

FilterQueryOption.cs

初始化它需要 content 和 parser. 嗯...感觉这个接口就比较底层了, 是我们要的了. 先不管 context, parser 怎么搞, 我们去看看它的 apply 做些什么.

ApplyTo

和我们猜测的一样, 里面搞了一个 queryable.where(expression). 它是利用了 FilterBinder.Bind 方法来把 string 转成 expression.

如果你有看上面的参考视频, 这个就是作者通过反射调用的方法. 因为这个 Bind 是 internal 方法来的, 所以他要反射.

FilterBinder.cs

好, 既然确定找对了路, 那么我们回去看看怎样从 0 做出来, context 和 parser 怎样弄.

ODataQueryContext.cs

初始化需要 EdmModel, ClrType, ODataPath.

EdmModel 就是我们每次 startup.cs 要搞的, 它和 EF Core 的 model 是同一个概念.

var odataBuilder = new ODataConventionModelBuilder();
odataBuilder.EntitySet<Product>("products");
odataBuilder.EnableLowerCamelCase();
var edmModel = odataBuilder.GetEdmModel();

ClrType 指的就是这一次的 $filter 的起头. OData 是对着 resource (entity) 的, 一定会有一个开始的 entity.

上面例子就是 typeof(Product).

ODataPath 我们参考它怎么做.

EnableQueryAttribute.cs

在 request 阶段就已经生产的, 全场找一下后它是这样做的

var entitySet = edmModel.FindDeclaredEntitySet("products");
var entitySetSegment = new EntitySetSegment(entitySet);
var odataPath = new ODataPath(new[] { entitySetSegment });

context 搞定, 下一个要做的是 parser.

ODataQueryOptionParser.cs (源码是在 odata.net library)

初始化有几个重载, 先挑一个最简单实现的呗.

model 有了, odataPath 有了,

queryOptions

Using Uri Parser 学的, 但这里只教到怎样 parser 出 filter clause 但是没有教怎样转成 expression.

搞定. 到这里我们就掌握了所有的资料了.

写 Demo

var odataBuilder = new ODataConventionModelBuilder();
odataBuilder.EntitySet<Product>("products");
odataBuilder.EnableLowerCamelCase();
var edmModel = odataBuilder.GetEdmModel(); // 做 edm model
var entitySet = edmModel.FindDeclaredEntitySet("products");
var entitySetSegment = new EntitySetSegment(entitySet);
var odataPath = new ODataPath(new[] { entitySetSegment }); // 做 odata path
var queryOptions = new Dictionary<string, string> // 定义 $filter query
{
["$filter"] = "id eq 2",
};
var queryOptionParser = new ODataQueryOptionParser(edmModel, odataPath, queryOptions); // 做 parser
var context = new ODataQueryContext(edmModel, typeof(Product), odataPath); // 做 context
var filterQueryOption = new FilterQueryOption("id eq 2", context, queryOptionParser); // 做 filter options
var productQuery = new List<Product> { new Product { Id = 1 }, new Product { Id = 2 } }.AsQueryable(); // 定义 queryable
var newQuery = filterQueryOption.ApplyTo(productQuery, new ODataQuerySettings()); // apply to
var result = newQuery.OfType<Product>().ToList(); // 得到结果

这样就实现了一个通过 OData 把 query string apply to queryable 的过程了。

除了 FilterQueryOption,其它的 OrderByQueryOption、SkipQueryOption、TopQueryOption 用法一模一样,只要拿 newQuery 继续 ApplyTo 就可以了。

注:FilterQueryOption("rawValue") 这个 rawValue 挺奇葩的,queryOptions 都已经表达了,为什么这里需要重复呢?

我测试了一下,其实只要不是放 null or empty string,你放任何值都可以通过,而且效果都是正确的。看源码好像这个 rawValue 是给其它 internal overload constructor 用来生成 queryOptions,估计是代码没写好呗。

如果我们不想 apply 只想获取到 expression 行不行?

不行, 除非像参考视频里那样, 通过反射去调用 internal 的 Bind 方法. 然后做 apply to 所有的动作, 除了最后一个 where.

总结

OData 确实很不错, 但想把 query string 转换成 expression 目前还没有一个 build-in 的 solution.

也有一些 library 可以做到类似的效果

Is there a ODATA query to linq where expression (ODATA to Linq )

本篇尝试探索如果利用 OData 现有的接口来尽量做到 query to expression. 同时期待 OData.Neo 带给开发者们更好的使用体验.

 

OData – Query to Expression的更多相关文章

  1. [转]Supporting OData Query Options in ASP.NET Web API 2

    本文转自:https://docs.microsoft.com/en-us/aspnet/web-api/overview/odata-support-in-aspnet-web-api/suppor ...

  2. Dynamics CRM2015 2015版本可用的OData Query Designer工具

    2015后很多工具无法使用,包括2011版的OData Query Designer,这里介绍一款可用的工具,Dynamics XRM Tools for CRM 2015,下载地址:https:// ...

  3. Dynamic CRM 2015学习笔记(5)CRM 2015 导入 OData Query Designer 解决方案

    以前一直使用OData Query Designer来生成.验证odata查询字符串,本想把它导入到CRM 2015的环境里,但报错: 到MSDN上发现太老版本的solution确实不能再导入到crm ...

  4. [转]Calling an OData Service From a .NET Client (C#)

    本文转自:https://docs.microsoft.com/en-us/aspnet/web-api/overview/odata-support-in-aspnet-web-api/odata- ...

  5. [转]Upgrading to Async with Entity Framework, MVC, OData AsyncEntitySetController, Kendo UI, Glimpse & Generic Unit of Work Repository Framework v2.0

    本文转自:http://www.tuicool.com/articles/BBVr6z Thanks to everyone for allowing us to give back to the . ...

  6. [转]Using OData from ASP.NET

    本文转自:http://www.drdobbs.com/windows/using-odata-from-aspnet/240168672 By Gastón Hillar, July 01, 201 ...

  7. ODATA WEB API(一)---扩展使用

    一.概述 时间也算充足,抽点时间总结下OData的常用的使用方式,开放数据协议(OData)是一个查询和更新数据的Web协议.OData应用了web技术如HTTP.Atom发布协议(AtomPub)和 ...

  8. 让Asp.Net WebAPI支持OData查询,排序,过滤。

    让Asp.Net WebAPI支持OData后,就能支持在url中直接输入排序,过滤条件了. 一.创建Asp.Net WebAPI项目: 二.使用NuGet安装Asp.Net WebAPI 2.2和O ...

  9. Linq之Expression进阶

    目录 写在前面 系列文章 表达式树解析 表达式树特性 编译表达树 总结 写在前面 让我们首先简单回顾一下上篇文章介绍的内容,上篇文章介绍了表达式树的基本概念(表达式树又称为“表达式目录树”,以数据形式 ...

  10. mvc api odata 查询选项之 $inlinecount ,$format 选项

    网上百度“odata 语法”会出来很多结果,其中有一项是比较一致的,那就是odata支持一下几种语法: $filter  条件表达式 -- 对应sql语句的where条件查询,如:/Categorie ...

随机推荐

  1. Windows 10 LTSC启用Microsoft Store的方法

    新建msreg.bat文件,并编辑内容如下: ========== @echo off :: BatchGotAdmin :------------------------------------- ...

  2. ABC357-C题解

    最近一直掉分,谔谔. 分析 发现机房里面除了我以外都用递归写的,那我就来讲一种非递归的吧. 考虑第 \(i\) 级地毯拆成九块以后其实就是八块第 \(i-1\) 级地毯与一块大小为 \(3^{i-1} ...

  3. 番外篇: go语言写的简要数据同步工具

    go-etl工具 作为go-etl工具的作者,想要安利一下这个小巧的数据同步工具,它在同步百万级别的数据时表现极为优异,基本能在几分钟完成数据同步. 1.它能干什么的? go-etl是一个数据同步工具 ...

  4. 基于Hive的大数据分析系统

    1.概述 在构建大数据分析系统的过程中,我们面对着海量.多源的数据挑战,如何有效地解决这些零散数据的分析问题一直是大数据领域研究的核心关注点.大数据分析处理平台作为应对这一挑战的利器,致力于整合当前主 ...

  5. FP分数规划在无线通信中的应用

    更多精彩内容请关注微信公众号 '优化与算法' 前言 在数学优化中,分数规划是线性分式规划的推广.分数规划中的目标函数是两个函数的比值,这两个函数通常是非线性的.要优化的比值通常描述系统的某种效率. 1 ...

  6. 【DataBase】MySQL 05 基础查询

    MySQL数据库 05 基础查询 视频参考自:P18 - P27 https://www.bilibili.com/video/BV1xW411u7ax 配套的SQL脚本:https://shimo. ...

  7. 【JavaWeb】HttpClient

    需要的依赖: <!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient --> <de ...

  8. 【Uni-App】UniApp转微信小程序发布应用

    参考地址: https://www.jianshu.com/p/a77b73f329e4 第一步,把原始Uni-App项目,转成微信小程序项目 点[发行]-- [小程序-微信(仅适用uni-app)] ...

  9. 全球最大开源模型Grok-1 —— 马斯克的大模型

    Grok官网: https://grok.x.ai/

  10. 修改linux系统时间由UTC改为CST(中国上海)时区

    Ubuntu系统 1. 将时间改为CST的中国上海时间: 命令: sudo ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime 或: sudo ...