当前位置: 首页 > news >正文

AScript定制left/right join查询语法

left join

标准LINQ查询的左连接写法如下:

1 from p in context.Persons 2 join a in context.AddressInfos on p.Id equals a.UserId into aa 3 from a in aa.DefaultIfEmpty() 4 select new { p.Id, p.Name, p.Age, MyAddress = a.Address };

简化后的left join语法如下:

1 from p in context.Persons 2 left join a in context.AddressInfos on p.Id equals a.UserId 3 select new { p.Id, p.Name, p.Age, MyAddress = a.Address };

如何实现呢?

1、在QueryNode中添加AddLeftJoin方法

1 public void AddLeftJoin(string varName, ITreeNode source, ITreeNode key1, ITreeNode key2) 2 { 3 string name1 = $"___{varName}___"; 4 AddJoin(varName, source, key1, key2, name1); 5 AddFrom(varName, new CallFuncNode { Name = "DefaultIfEmpty", Args = new ITreeNode[] { new VariableNode(name1) } }); 6 }

可以看到,AddLeftJoin方法中我们手动增加了join ... into xxxfrom ... xxx.DefaultIfEmpty()语句。

2、在FromTokenHandler中添加left join解析

1 public void Build(DefaultSyntaxAnalyzer analyzer, TokenAnalyzingArgs e) 2 { 3 e.IsHandled = true; 4 var queryNode = e.Ignore ? null : new QueryNode(); 5 var createFullOptions = (e.Options.CreateFullTreeNode ?? false) ? e.Options : new BuildOptions(e.Options) { CreateFullTreeNode = true }; 6 // 解析from语句 7 BuildFrom(analyzer, e, createFullOptions, queryNode); 8 // 解析后续linq语句 9 while (true) 10 { 11 var token = e.TokenReader.Read(); 12 ... 13 else if (token.Value.IsSymbol("join")) 14 { 15 BuildJoin(analyzer, e, createFullOptions, queryNode); 16 } 17 else if (token.Value.IsSymbol("left")) 18 { 19 BuildLeftJoin(analyzer, e, createFullOptions, queryNode); 20 } 21 else if (token.Value.IsSymbol("right")) 22 { 23 BuildRightJoin(analyzer, e, createFullOptions, queryNode); 24 } 25 ... 26 } 27 // 将LINQ语句添加到语法树中 28 if (!e.Ignore) 29 { 30 e.TreeBuilder.AddData(e.BuildContext, e.ScriptContext, e.Options, e.Control, queryNode); 31 } 32 } 33 34 private void BuildLeftJoin(DefaultSyntaxAnalyzer analyzer, TokenAnalyzingArgs e, BuildOptions createFullOptions, QueryNode queryNode) 35 { 36 analyzer.ValidateNextToken(e.TokenReader, "join"); 37 38 var varToken = analyzer.ValidateNextToken(e.TokenReader, ETokenType.Word); 39 analyzer.ValidateNextToken(e.TokenReader, "in"); 40 41 var source = analyzer.BuildOneStatement(e.BuildContext, e.ScriptContext, e.Options, e.TokenReader, e.Control, e.Ignore, _OnTokens); 42 43 analyzer.ValidateNextToken(e.TokenReader, "on"); 44 45 var key1 = analyzer.BuildOneStatement(e.BuildContext, e.ScriptContext, createFullOptions, e.TokenReader, e.Control, e.Ignore, _EqualsTokens); 46 analyzer.ValidateNextToken(e.TokenReader, "equals"); 47 var key2 = analyzer.BuildOneStatement(e.BuildContext, e.ScriptContext, createFullOptions, e.TokenReader, e.Control, e.Ignore, _Join2EndTokens); 48 49 queryNode?.AddLeftJoin(varToken.Value.Value, source, key1, key2); 50 }

这样我们就实现了left join语法,以后在脚本中写左连接语句就方便多了。

sqlite查询完整示例

1 using (var context = new TestSqliteContext()) 2 { 3 string s = @" 4 var q = from p in context.Persons 5 left join a in context.AddressInfos on p.Id equals a.UserId 6 select new { p.Id, p.Name, p.Age, MyAddress = a.Address }; 7 q.ToList(); 8 "; 9 var script = new Script(); 10 script.Context.SetVar("context", context); 11 var list = script.Eval(s); 12 Console.WriteLine(JsonConvert.SerializeObject(list, Formatting.Indented)); 13 }

生成的sqlite查询语句为:

1 SELECT "p"."Id", "p"."Name", "p"."Age", "a"."Address" AS "MyAddress" 2 FROM "Persons" AS "p" 3 LEFT JOIN "AddressInfos" AS "a" ON "p"."Id" = "a"."UserId"

二、right join

标准LINQ查询要实现右连接,只能用左连接语句并交换2个表的位置来实现右连接功能。

比如上面的示例中把左连接AddressInfos表改为右连接,则交换2个表位置:

1 from a in context.AddressInfos 2 left join p in context.Persons on a.UserId equals p.Id 3 select new { p.Id, p.Name, p?.Age, MyAddress = a.Address };

虽然能实现右连接效果,但是写法不太符合我们的逻辑,使用right join语法如下:

1 from p in context.Persons 2 right join a in context.AddressInfos on p.Id equals a.UserId 3 select new { p.Id, p.Name, p?.Age, MyAddress = a.Address };

如何实现right join语法呢?

1、在QueryNode中添加AddRightJoin方法

1 public void AddRightJoin(string varName, ITreeNode source, ITreeNode key1, ITreeNode key2) 2 { 3 var right = _Source; 4 var rightName = _CurrentVarName; 5 _Source = source; 6 _CurrentVarName = varName; 7 AddLeftJoin(rightName, right, key2, key1); 8 }

没错,就是交换2个表的位置使用左连接来实现。

2、在FromTokenHandler中添加right join解析

1 private void BuildRightJoin(DefaultSyntaxAnalyzer analyzer, TokenAnalyzingArgs e, BuildOptions createFullOptions, QueryNode queryNode) 2 { 3 analyzer.ValidateNextToken(e.TokenReader, "join"); 4 5 var varToken = analyzer.ValidateNextToken(e.TokenReader, ETokenType.Word); 6 analyzer.ValidateNextToken(e.TokenReader, "in"); 7 8 var source = analyzer.BuildOneStatement(e.BuildContext, e.ScriptContext, e.Options, e.TokenReader, e.Control, e.Ignore, _OnTokens); 9 10 analyzer.ValidateNextToken(e.TokenReader, "on"); 11 12 var key1 = analyzer.BuildOneStatement(e.BuildContext, e.ScriptContext, createFullOptions, e.TokenReader, e.Control, e.Ignore, _EqualsTokens); 13 analyzer.ValidateNextToken(e.TokenReader, "equals"); 14 var key2 = analyzer.BuildOneStatement(e.BuildContext, e.ScriptContext, createFullOptions, e.TokenReader, e.Control, e.Ignore, _Join2EndTokens); 15 16 queryNode?.AddRightJoin(varToken.Value.Value, source, key1, key2); 17 }

sqlite查询完整示例

1 using (var context = new TestSqliteContext()) 2 { 3 string s = @" 4 var q = from p in context.Persons 5 right join a in context.AddressInfos on p.Id equals a.UserId 6 select new { p.Id, p.Name, p?.Age, MyAddress = a.Address }; 7 q.ToList(); 8 "; 9 var script = new Script(); 10 script.Context.SetVar("context", context); 11 var list = script.Eval(s); 12 Console.WriteLine(JsonConvert.SerializeObject(list, Formatting.Indented)); 13 }

生成的sqlit查询语句为(左连接交换2个表位置):

1 SELECT "p"."Id", "p"."Name", "p"."Age", "a"."Address" AS "MyAddress" 2 FROM "AddressInfos" AS "a" 3 LEFT JOIN "Persons" AS "p" ON "a"."UserId" = "p"."Id"

三、结束语

虽然是2个小小的语法,却大大提高了我们的脚本编写效率。

AScript开源地址:https://gitee.com/rockey627/AScript

分类: C#

免责声明:本内容来自平台创作者,博客园系信息发布平台,仅提供信息存储空间服务。

好文要顶 关注我 收藏该文 微信分享

rockey627
粉丝 - 5 关注 - 5

+加关注

1

0

升级成为会员

« 上一篇: AScript异步执行与await关键字
» 下一篇: AScript之事件处理脚本

posted @ 2026-05-26 22:15 rockey627 阅读(135) 评论(0) 收藏 举报

刷新页面返回顶部

登录后才能查看或发表评论,立即 登录 或者 逛逛 博客园首页

编辑推荐:

公告

昵称: rockey627
园龄: 14年
粉丝: 5
关注: 5

+加关注

<2026年6月>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

常用链接

最新随笔

我的标签

随笔分类

随笔档案

阅读排行榜

评论排行榜

推荐排行榜

http://www.jsqmd.com/news/1067260/

相关文章:

  • 蚂蚁面试官:“你的 Agent 怎么触发记忆提取?“ 我不屑:“每轮结束触发一次呗。“ 他冷笑:“那 Claude Code 为什么不这么设计?“ 我:……
  • 2026 年 AI 音效赛道技术现状:三款国产方案横向对比
  • 网络管理作业
  • C语言小游戏 — 三子棋
  • OpenClaw-RL
  • 运维监控大屏踩坑记:一条 SQL 的“CASE 陷阱”与跨库优化实践
  • 文字编辑器EditPlus
  • 2026年SEO+GEO优化指南:搜索排名机制解析与实用工具推荐
  • 搬瓦工 KiwiVM 面板免费 AI 助手 Amy 功能演示 | 告别繁琐的命令行
  • 【Azure Function App】本地调试PowerShell Function时需要注意两类错误:加载失败和认证失败
  • 前端学习笔记-vue组件通信常用方式
  • 在本地运行任意 Hugging Face 模型:GGUF 完全指南
  • 2026最权威AI论文写作工具榜单:这些被高校和导师偷偷推荐的软件你还没用?
  • OpenTracing Python:分布式追踪的标准 API
  • 先说基因:一个做自动化起家,一个做采集起家
  • AI写作辅助软件的使用规范:如何让AI生成内容通过严格学术审查
  • 我做了一个只用来搜歌词的小 App
  • 非对称密码体系的密码分析方法研究
  • Pendulum:Python 日期时间处理的终极解决方案
  • 告别新手级RAG!一文掌握专业级后检索优化之「校正」
  • Edge浏览器停止更新,并回退到老版本方法
  • 深入 .NET AI Agent 开发:利用 Microsoft.Agents.AI 提取思考、调用工具与执行脚本
  • Manim物理模拟:别自己写欧拉了!
  • 古典密码 - 维吉尼亚密码破解
  • [APM32F4] 跟随 Fabrice Bellard 的脚步,把 MicroQuickJS 移植到 APM32F427
  • 2026 佛山传统企业升级|短视频矩阵赋能,加快数字化内容建设
  • 在线 AI 开发平台-MonkeyCode
  • 吉他选购指南2026年入门级1000-2000元横评:参数对比+真实评测
  • 每日一个开源项目(第138篇):OpenMontage - 把 AI 编程助手变成完整的视频制作团队
  • HAProxy 学习总结