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 xxx和from ... 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) 收藏 举报
刷新页面返回顶部
登录后才能查看或发表评论,立即 登录 或者 逛逛 博客园首页
编辑推荐:
- 让 Agent 在对话中成长:自进化机制的五层实现
- 代码之外:一个技术人的职场困境与自我和解
- 贩卖焦虑的时代,我终于接住了真实的焦虑
- 工良吐槽篇:万字长文细说 AI 落地之笑谈
- 代码是 AI 写的,生产事故谁背锅?
公告
昵称: rockey627
园龄: 14年
粉丝: 5
关注: 5
+加关注
| |||||||||
| 日 | 一 | 二 | 三 | 四 | 五 | 六 | |||
|---|---|---|---|---|---|---|---|---|---|
| 31 | 1 | 2 | 3 | 4 | 5 | 6 | |||
| 7 | 8 | 9 | 10 | 11 | 12 | 13 | |||
| 14 | 15 | 16 | 17 | 18 | 19 | 20 | |||
| 21 | 22 | 23 | 24 | 25 | 26 | 27 | |||
| 28 | 29 | 30 | 1 | 2 | 3 | 4 | |||
| 5 | 6 | 7 | 8 | 9 | 10 | 11 | |||
常用链接
- 我的随笔
- 我的评论
- 我的参与
- 最新评论
- 我的标签
最新随笔
- 1. 基于AScript的SQL脚本语言发布啦!
- 2. AScript之事件处理脚本
- 3. AScript定制left/right join查询语法
- 4. AScript异步执行与await关键字
- 5. AScript如何实现LINQ语法
- 6. AScript之匿名类型与动态类型
- 7. AScript中一个很有意思的语法
- 8. 基于AScript的python3脚本语言发布啦!
- 9. AScript之eval函数详解
- 10. AScript函数体系详解
我的标签
- Script(13)
- C#(13)
- .NET(13)
- 动态脚本(12)
- Expression(11)
- Eval(11)
- Function(6)
- sql(3)
- python3(1)
- python(1)
- 更多
随笔分类
- C#(14)
随笔档案
- 2026年6月(2)
- 2026年5月(7)
- 2026年4月(5)
阅读排行榜
- 1. AScript - C#轻量级动态脚本引擎(476)
- 2. 基于AScript的python3脚本语言发布啦!(247)
- 3. AScript函数体系详解(210)
- 4. 基于AScript的SQL脚本语言发布啦!(199)
- 5. AScript如何实现中文脚本引擎(180)
评论排行榜
- 1. AScript - C#轻量级动态脚本引擎(1)
推荐排行榜
- 1. AScript - C#轻量级动态脚本引擎(8)
- 2. AScript扩展多种脚本语言(3)
- 3. AScript如何实现中文脚本引擎(3)
- 4. AScript:一个好用的C#动态脚本解析执行库(3)
