首页 > 基础资料 博客日记
AScript定制left/right join查询语法
2026-05-26 22:30:02基础资料围观10次
极客资料网推荐AScript定制left/right join查询语法这篇文章给大家,欢迎收藏极客资料网享受知识的乐趣
AScript是一个开源的C#动态脚本解析执行引擎,支持扩展自定义语法。
在之前的文章《AScript如何实现LINQ语法》中实现了C#标准LINQ查询语法,但并不支持left join/right join语句,不过.NET10在Queryable/Enumerable中新增了LeftJoin/RightJoin扩展方法(LINQ查询语法中仍然不支持left join/right join写法)。
本篇将在LINQ语法的基础上增加left join和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
文章来源:https://www.cnblogs.com/rockey627/p/20176770
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:jacktools123@163.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:jacktools123@163.com进行投诉反馈,一经查实,立即删除!
标签:

