炒股全靠蒙 發表於 2025-4-2 22:32:00

ShadowSql.net之sql拼写神器

<p>我正在开发的一个.net sql拼写工具(SqlBuilder),也可以算是ORM,命名为ShadowSql</p>
<p>本工具的作用就是帮码农拼写sql,对标开源项目SqlKata。</p>
<p>在项目里面直接拼写sql很容易出错,是件很Low的事情,所以我们需要ORM工具。</p>
<p>但是有些ORM很重,很担心造成性能问题,这就是开发本工具的出发点.</p>
<p>本工具很小、不依赖第三方包,不使用反射,应该支持AOT原生编译,不过我还没测试。</p>
<p>本工具最大的特点就是性能好,省内存,拼接sql从头到尾只使用一个StringBuilder。</p>
<p>跨平台、可扩展、支持多种数据库,可以自定义数据库方言,支持net7.0;net8.0;net9.0;netstandard2.0;netstandard2.1。</p>
<p>本工具最适合搭配Dapper使用,所以附带了一个Dapper扩展。当然直接搭配ado.net也是可以的。</p>
<p>sql操作用的最多也是最复杂的就是查询,本工具包含两套查询模式:sql模式和逻辑模式。</p>
<p>一、先介绍sql查询模式</p>
<p>1、支持按原生sql进行查询,示例如下:</p>
<div class="cnblogs_code">
<pre>      <span style="color: rgba(0, 0, 255, 1)">var</span> query = db.From(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Users</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
            .ToSqlQuery()
            .Where(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Id=@Id</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Status=@Status</span><span style="color: rgba(128, 0, 0, 1)">"</span>);</pre>
</div>
<p>sql:&nbsp;SELECT * FROM WHERE Id=@Id AND Status=@Status</p>
<p>2、支持按逻辑查询</p>
<div class="cnblogs_code">
<pre>      <span style="color: rgba(0, 0, 255, 1)">var</span> query = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> UserTable()
            .ToSqlQuery()
            .Where(Id.EqualValue(</span><span style="color: rgba(128, 0, 128, 1)">100</span>));</pre>
</div>
<p>sql:&nbsp;SELECT * FROM WHERE =100</p>
<p>3、支持GroupBy</p>
<div class="cnblogs_code">
<pre>      <span style="color: rgba(0, 0, 255, 1)">var</span> table = db.From(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Users</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
      </span><span style="color: rgba(0, 0, 255, 1)">var</span> groupBy =<span style="color: rgba(0, 0, 0, 1)"> table.ToSqlQuery()
            .ColumnEqualValue(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Age</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 128, 1)">20</span><span style="color: rgba(0, 0, 0, 1)">)
            .GroupBy(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">CityId</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
            .Having(g </span>=&gt; g.Aggregate(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">MAX</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Level</span><span style="color: rgba(128, 0, 0, 1)">"</span>).GreaterValue(<span style="color: rgba(128, 0, 128, 1)">9</span>));</pre>
</div>
<p>sql:&nbsp;SELECT * FROM WHERE =20 GROUP BY HAVING MAX()&gt;9</p>
<p>4、支持联表</p>
<div class="cnblogs_code">
<pre>      <span style="color: rgba(0, 0, 255, 1)">var</span> employees = db.From(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Employees</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
      </span><span style="color: rgba(0, 0, 255, 1)">var</span> departments = db.From(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Departments</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);

      </span><span style="color: rgba(0, 0, 255, 1)">var</span> joinOn =<span style="color: rgba(0, 0, 0, 1)"> employees.SqlJoin(departments)
            .On(</span><span style="color: rgba(0, 0, 255, 1)">static</span> (t1, t2) =&gt; t1.Field(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">DepartmentId</span><span style="color: rgba(128, 0, 0, 1)">"</span>).Equal(t2.Field(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Id</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)));
      </span><span style="color: rgba(0, 0, 255, 1)">var</span> joinTable =<span style="color: rgba(0, 0, 0, 1)"> joinOn.Root
            .Where(join </span>=&gt; join.From(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">t2</span><span style="color: rgba(128, 0, 0, 1)">"</span>).Field(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Manager</span><span style="color: rgba(128, 0, 0, 1)">"</span>).EqualValue(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">CEO</span><span style="color: rgba(128, 0, 0, 1)">"</span>));</pre>
</div>
<p>sql:&nbsp;SELECT * FROM AS t1 INNER JOIN AS t2 ON t1.=t2. WHERE t2.='CEO'</p>
<p>二、逻辑模式</p>
<p>以上功能逻辑模式大多都支持,逻辑模式是按And、Or来查询的。没有where、having、on等关键字</p>
<p>逻辑模式不支持按原生sql查询,当然封装为逻辑对象就可以了,但不推荐这么做。</p>
<p>所谓逻辑就是与、或、非运算。</p>
<p>Sql模式也支持逻辑对象,从这个层面上说sql模式功能更全,sql模式查询对象就是包含一个复合逻辑对象+Sql查询对象。</p>
<p>逻辑模式一般执行速度更快、内存消耗更少。</p>
<p>1、单表查询</p>
<div class="cnblogs_code">
<pre>      <span style="color: rgba(0, 0, 255, 1)">var</span> query = db.From(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Users</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
            .ToQuery()
            .And(_id.Equal())
            .And(_status.Equal(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Status</span><span style="color: rgba(128, 0, 0, 1)">"</span>));</pre>
</div>
<div class="cnblogs_code">
<pre>      <span style="color: rgba(0, 0, 255, 1)">var</span> query = db.From(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Users</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
            .ToOrQuery()
            .Or(_id.Equal())
            .Or(_status.Equal(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Status</span><span style="color: rgba(128, 0, 0, 1)">"</span>));</pre>
</div>
<p>SELECT * FROM WHERE =@Id AND =@Status</p>
<p>SELECT * FROM WHERE =@Id OR =@Status</p>
<p>2、GroupBy</p>
<div class="cnblogs_code">
<pre>      <span style="color: rgba(0, 0, 255, 1)">var</span> groupBy =<span style="color: rgba(0, 0, 0, 1)"> table.ToQuery()
            .And(Age.EqualValue(</span><span style="color: rgba(128, 0, 128, 1)">20</span><span style="color: rgba(0, 0, 0, 1)">))
            .GroupBy(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">CityId</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
            .And(Level.Max().GreaterValue(</span><span style="color: rgba(128, 0, 128, 1)">9</span>));</pre>
</div>
<p>sql:&nbsp;SELECT * FROM WHERE =20 GROUP BY HAVING MAX()&gt;9</p>
<p>3、联表</p>
<div class="cnblogs_code">
<pre>      CommentTable c = <span style="color: rgba(0, 0, 255, 1)">new</span>(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">c</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
      PostTable p </span>= <span style="color: rgba(0, 0, 255, 1)">new</span>(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">p</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
      </span><span style="color: rgba(0, 0, 255, 1)">var</span> joinOn =<span style="color: rgba(0, 0, 0, 1)"> c.Join(p)
            .And(c.PostId.Equal(p.Id));
      </span><span style="color: rgba(0, 0, 255, 1)">var</span> query =<span style="color: rgba(0, 0, 0, 1)"> joinOn.Root
            .And(c.Pick.Equal())
            .And(p.Author.Equal())</span></pre>
</div>
<p>sql: SELECT * FROM AS c INNER JOIN AS p ON c.=p. where c.=@Pick AND p.=@Author</p>
<p>篇幅有限,还有很多功能没法在这里一一列举,欢迎大家去探索,抽出时间我也会再发新文章来做更详细的介绍。</p>
<p>三、两种模式与SqlKata对比速度都更快,消耗内存也更少</p>
<p><img src="https://img2024.cnblogs.com/blog/248830/202504/248830-20250402222516463-294369242.png" alt="" loading="lazy"></p>
<p>&nbsp;更多信息可以到github上查询,或下载代码自己测试一下</p>
<p>四、源码托管在github上</p>
<p>仓库地址:&nbsp;https://github.com/donetsoftwork/Shadow</p>
<p>如果大家喜欢请动动您发财的小手手帮忙点一下Star。</p>
<p>有什么建议也可以反馈给我,该项目还在开发中,还可能会增加更多有趣的功能。</p>
<p>而且我还计划为这个工具再开发一个精简版本,以求更好的性能。</p>
<p>&nbsp;</p><br><br>
来源:https://www.cnblogs.com/xiangji/p/18806891
頁: [1]
查看完整版本: ShadowSql.net之sql拼写神器