AScript定制left/right join查询语法

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

常用链接

最新随笔

我的标签

随笔分类

随笔档案

阅读排行榜

评论排行榜

推荐排行榜