前言

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. .NET开源、简单、实用的数据库文档生成工具

    前言 今天大姚给大家分享一款.NET开源(MIT License).免费.简单.实用的数据库文档(字典)生成工具,该工具支持CHM.Word.Excel.PDF.Html.XML.Markdown等多 ...

  2. oeasy教您玩转vim - 29 - # 垂直翻页

    ​ 垂直翻页 回忆上节课内容 我们上次了解了横向滚动的相关信息 横滚幅度 - sidescroll 横滚留位 - sidescrolloff 自动换行 - wrap g j.g k 可以逐行上下移动 ...

  3. [WPF] 脱机环境实现支持拼音模糊搜索的AutoCompleteBox

    AutoCompleteBox是一个常见的提高输入效率的组件,很多WPF的第三方控件库都提供了这个组件,但基本都是字符串的子串匹配,不支持拼音模糊匹配,例如无法通过输入ldh或liudehua匹配到刘 ...

  4. CCF 无线网络

    题目原文 问题描述(题目链接登陆账号有问题,要从这个链接登陆,然后点击"模拟考试",进去找本题目) 试题编号: 201403-4 试题名称: 无线网络 时间限制: 1.0s 内存限 ...

  5. 《最新出炉》系列入门篇-Python+Playwright自动化测试-55- 上传文件 (非input控件)- 中篇

    1.简介 在实际工作中,我们进行web自动化的时候,文件上传是很常见的操作,例如上传用户头像,上传身份证信息等.所以宏哥打算按上传文件的分类对其进行一下讲解和分享. 2.上传文件的API(非input ...

  6. python统计班级学生

    python统计班级学生 如下场景: 假设我有一个学生类和一个班级类,想要实现的功能为:    执行班级人数增加的操作.获得班级的总人数:    学生类继承自班级类,每实例化一个学生,班级人数都能增加 ...

  7. QT入门学习记录01

    目录 前言 一.Qt安装 二.创建一个Qt工程 三.基类的区别和常用函数 1.QWidget 1.1 设置窗口标题 1.2 设置窗口大小和显示位置 1.3 显示窗口 1.4 隐藏窗口 1.5 改变窗口 ...

  8. T800机器人图片 —— 强大的好莱坞电影工业,T800机器人模型也如此精细真实!

    视频地址: https://www.ixigua.com/6764744689003266571

  9. 图表全能王(ChartStudio) 上架VisionPro!

    图表全能王(ChartStudio) - 终极图表制作工具!支持条形图.折线图.面积图.柱形图.条形图.饼图.玫瑰图.雷达图.牛肉图.风琴图.旭日图.桑基图等图表. https://apps.appl ...

  10. Apache DolphinScheduler 3.1.8 保姆级教程【安装、介绍、项目运用、邮箱预警设置】轻松拿捏!

    概述 Apache DolphinScheduler 是一个分布式易扩展的可视化 DAG 工作流任务调度开源系统.适用于企业级场景,提供了一个可视化操作任务.工作流和全生命周期数据处理过程的解决方案. ...