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加关注10升级成为会员« 上一篇 AScript异步执行与await关键字» 下一篇 AScript之事件处理脚本posted 2026-05-26 22:15 rockey627 阅读(135) 评论(0) 收藏 举报刷新页面返回顶部登录后才能查看或发表评论立即 登录 或者 逛逛 博客园首页编辑推荐让 Agent 在对话中成长自进化机制的五层实现代码之外一个技术人的职场困境与自我和解贩卖焦虑的时代我终于接住了真实的焦虑工良吐槽篇万字长文细说 AI 落地之笑谈代码是 AI 写的生产事故谁背锅公告昵称 rockey627园龄 14年粉丝 5关注 5加关注2026年6月日一二三四五六311234567891011121314151617181920212223242526272829301234567891011常用链接我的随笔我的评论我的参与最新评论我的标签最新随笔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)