陈国祥 發表於 2025-4-4 01:04:00

ShadowSql.net之借Dapper打造高性能ORM及百变魔法

<p>ShadowSql专职拼写sql,要想做为ORM就需要借高人之手</p>
<p>我们要借的就是Dapper,Dapper以高性能著称,ShadowSql搭配Dapper就是强强联手</p>
<p>为此本项目内置了一个子项目Dapper.Shadow就是Dapper扩展</p>
<p>以下是Dapper.Shadow的示例</p>
<p>一、配置Dapper执行器</p>
<div class="cnblogs_code">
<pre>ISqlEngine engine = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> SqliteEngine();
</span>IDbConnection connection = <span style="color: rgba(0, 0, 255, 1)">new</span> SqliteConnection(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Data Source=file::memory:;Cache=Shared</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
</span>IExecutor executor = <span style="color: rgba(0, 0, 255, 1)">new</span> DapperExecutor(engine, connection);</pre>
</div>
<p>其中engine数据库(及方言)的配置对象,现在支持5种,分别是MsSql、MySql、Oracle、Postgres和Sqlite</p>
<p>实现ISqlEngine可以自定义数据库类型或者方言的支持</p>
<p>二、读取整张表</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">var</span> students = Executor.From(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Students</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
    .ToDapperSelect()
    .Get</span>&lt;Student&gt;();</pre>
</div>
<p>三、查询数据</p>
<p>1、SqlQuery查询数据</p>
<div class="cnblogs_code">
<pre>      <span style="color: rgba(0, 0, 255, 1)">var</span> students = Executor.From(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Students</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)">Age=10</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
            .ToDapperSelect()
            .Get</span>&lt;Student&gt;();</pre>
</div>
<div class="cnblogs_code">
<pre>      <span style="color: rgba(0, 0, 255, 1)">var</span> students = Executor.From(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Students</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
            .ToSqlQuery()
            .ColumnValue(</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)">10</span><span style="color: rgba(0, 0, 0, 1)">)
            .ToDapperSelect()
            .Get</span>&lt;Student&gt;();</pre>
</div>
<div class="cnblogs_code">
<pre>      <span style="color: rgba(0, 0, 255, 1)">var</span> table = <span style="color: rgba(0, 0, 255, 1)">new</span> StudentTable(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Students</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> students =<span style="color: rgba(0, 0, 0, 1)"> table.ToSqlQuery()
            .Where(table.Age.EqualValue(</span><span style="color: rgba(128, 0, 128, 1)">10</span><span style="color: rgba(0, 0, 0, 1)">))
            .ToSelect()
            .Get</span>&lt;Student&gt;(Executor);</pre>
</div>
<div class="cnblogs_code">
<pre>      <span style="color: rgba(0, 0, 255, 1)">var</span> students = <span style="color: rgba(0, 0, 255, 1)">new</span> StudentTable(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Students</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
            .ToSqlQuery()
            .Where(table </span>=&gt; table.Age.EqualValue(<span style="color: rgba(128, 0, 128, 1)">10</span><span style="color: rgba(0, 0, 0, 1)">))
            .ToSelect()
            .Get</span>&lt;Student&gt;(Executor);</pre>
</div>
<div class="cnblogs_code">
<pre>      <span style="color: rgba(0, 0, 255, 1)">var</span> students = <span style="color: rgba(0, 0, 255, 1)">new</span> Table(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Students</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
            .DefineColums(</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(0, 0, 0, 1)">)
            .ToSqlQuery()
            .Where(student </span>=&gt; student.Column(<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>).EqualValue(<span style="color: rgba(128, 0, 128, 1)">10</span><span style="color: rgba(0, 0, 0, 1)">))
            .ToDapperSelect(Executor)
            .Get</span>&lt;Student&gt;();</pre>
</div>
<p>主要分以下三种</p>
<p>1.1 把执行器当数据库对象,这样查询就自带执行器,可以直接执行</p>
<p>1.2 执行时把执行器当参数传入</p>
<p>1.3 先查询,调用ToDapperSelect创建可执行对象</p>
<p>&nbsp;</p>
<p>2、Query查询数据</p>
<div class="cnblogs_code">
<pre>      <span style="color: rgba(0, 0, 255, 1)">var</span> table = <span style="color: rgba(0, 0, 255, 1)">new</span> StudentTable(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Students</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> students =<span style="color: rgba(0, 0, 0, 1)"> table.ToQuery()
            .And(table.Age.EqualValue(</span><span style="color: rgba(128, 0, 128, 1)">10</span><span style="color: rgba(0, 0, 0, 1)">))
            .ToSelect()
            .Get</span>&lt;Student&gt;(Executor);</pre>
</div>
<div class="cnblogs_code">
<pre>      <span style="color: rgba(0, 0, 255, 1)">var</span> students = Executor.From(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Students</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
            .ToQuery()
            .And(table </span>=&gt; table.Field(<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>).EqualValue(<span style="color: rgba(128, 0, 128, 1)">10</span><span style="color: rgba(0, 0, 0, 1)">))
            .ToDapperSelect()
            .Get</span>&lt;Student&gt;();</pre>
</div>
<div class="cnblogs_code">
<pre>      <span style="color: rgba(0, 0, 255, 1)">var</span> table = <span style="color: rgba(0, 0, 255, 1)">new</span> StudentTable(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Students</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> students =<span style="color: rgba(0, 0, 0, 1)"> table.ToQuery()
            .And(table.Age.EqualValue(</span><span style="color: rgba(128, 0, 128, 1)">10</span><span style="color: rgba(0, 0, 0, 1)">))
            .ToDapperSelect(Executor)
            .Get</span>&lt;Student&gt;();</pre>
</div>
<p>&nbsp;</p>
<p>查询方式多样,限与篇幅没法一一</p>
<p>以上示例邮件可以清晰显示ShadowSql和Dapper可以无缝对接</p>
<p>&nbsp;</p>
<p>四、查询数据百变魔法,值变参数</p>
<p>看以下示例,我们只是用ParametricExecutor代替DapperExecutor</p>
<div class="cnblogs_code">
<pre>      <span style="color: rgba(0, 0, 255, 1)">var</span> connection = <span style="color: rgba(0, 0, 255, 1)">new</span> SqliteConnection(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Data Source=file::memory:;Cache=Shared</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> excutor = <span style="color: rgba(0, 0, 255, 1)">new</span> ParametricExecutor(<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> SqliteEngine(), connection);
      </span><span style="color: rgba(0, 0, 255, 1)">var</span> students = excutor.From(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Students</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
            .ToQuery()
            .And(table </span>=&gt; table.Field(<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>).EqualValue(<span style="color: rgba(128, 0, 128, 1)">10</span><span style="color: rgba(0, 0, 0, 1)">))
            .ToDapperSelect()
            .Get</span>&lt;Student&gt;();</pre>
</div>
<p><img src="https://img2024.cnblogs.com/blog/248830/202504/248830-20250404014337079-1272193510.png" alt="" loading="lazy"></p>
<p>&nbsp;查询还是正常的,但调试到Dapper内部,看sql发生了变化。</p>
<p>本来sql应该是SELECT * FROM "Students" WHERE "Age"=10变成了SELECT * FROM "Students" WHERE "Age"=@p1</p>
<p>本来参数应该是默认值null的,结果填充了参数p1,值为10</p>
<p>做过sql注入安全的同学应该很清楚查询值为字符串导致sql注入的风险</p>
<p>尽管该工具对字符串查询值有做过滤的规则,但我们知道这还远远不够</p>
<p>我们应该对字符串查询全部用参数化,但这可能增加了太多工作量,特别是接手祖传的老项目</p>
<p>这个魔法就可以解决这个棘手的问题</p>
<p>以上是用Query举例,用SqlQuery也是同理,ParametricExecutor会把查询值转为参数化查询,并与传入的参数做合并</p>
<p>&nbsp;</p>
<p>就这样实现了一个精简别致的高性能ORM,您也可以使用ShadowSql和Dapper来DIY属于自己的高性能ORM</p>
<p>&nbsp;</p><br><br>
来源:https://www.cnblogs.com/xiangji/p/18808611
頁: [1]
查看完整版本: ShadowSql.net之借Dapper打造高性能ORM及百变魔法