共产主义的接班人 發表於 2017-3-23 09:41:00

.net平台的MongoDB使用

<h1><strong>前言</strong></h1>
<p>  最近花了点时间玩了下MongoDB.Driver,进行封装了工具库,平常也会经常用到MongoDB,因此写一篇文章梳理知识同时把自己的成果分享给大家。</p>
<p>  本篇会设计到Lambda表达式的解析,有兴趣的同学也看看我之前写的《<strong><span class="postTitle2">表达式树的解析</span></strong>》。</p>
<p>  文章最后会给出源码下载地址。</p>
<h1>MongoDB简介</h1>
<p>  MongoDB是一个基于分布式文件存储的非关系型数据库,相比于其他NoSql它支持复杂的查询。</p>
<p>  文本是类似JSON的BSON格式,BSON是在JSON的基础上进化:更快的遍历、操作更简易、更多的数据类型。因此MongoDB可以存储比较复杂的数据类型,同样也支持建立索引。</p>
<p>  MongoDB的概念有:</p>
<ul>
<li>DataBase(库)</li>
<li>Collections(集合),类似于关系型数据库的表</li>
<li><span class="op_dict_text2">Document(文档),类似于关系型数据库的一条数据</span></li>
</ul>
<p>  <img src="https://images2015.cnblogs.com/blog/488722/201703/488722-20170323095004236-1540698134.jpg" alt="" width="735" height="510"></p>
<h1>MongoDB优缺点</h1>
<ul>
<li>
<h2>优点</h2>
</li>
</ul>
<ol>
<li>高效性,内置GridFS,从而达到海量数据存储,并且满足大数据集的快速范围查询。</li>
<li>高扩展性,分片使MongoDB的有更高的吞吐量,复制使MongoDB更高的可用性。</li>
<li><span style="font-family: 微软雅黑">BSON</span>文档,易于理解、查看,</li>
<li>免费</li>
</ol>
<ul>
<li>
<h2>缺点</h2>
</li>
</ul>
<ol>
<li>不支持事务</li>
<li>不支持表关联</li>
<li>不耗CPU却耗内存</li>
<li>没有成熟的管理工具</li>
</ol>
<h1>MongoDB使用场景</h1>
<p>  拥有高效的存储的特点,让MongoDB用在操作日志记录是非常流行的做法。</p>
<p>  随着版本的升级提供更加强大的功能,产品逐渐成熟用在主业务也很多,例如电商行业的订单系统与包裹跟踪模块,海量的主订单与订单明细,包裹的状态变更信息。</p>
<p>  然而因为BSON文档的存储方式,使平常的开发的思维模式有所变更。举个栗子,传统用关系型数据库,订单模块就会分主订单表和订单明细表,创建订单就会用事务同时添加两表的数据,查找订单也会通过两表关联查询出来。但是使用MongoDB,主订单表与其明细,将会以一个完整的对象保存为文档。</p>
<p>  也因为不支持事务、表关联的原因,它更加适合用作于一个完整的业务模块。</p>
<p>  部分朋友会带着一个问题,非关系型数据库和关系型数据库哪个更好。我认为,谁都无法代替谁,一般情况下,非关系型数据库更多的作为关系型数据库扩展,用好了效果甚佳,滥用了只会寸步难行。</p>
<p>  <img src="https://images2015.cnblogs.com/blog/488722/201703/488722-20170323093504596-1582821088.png" alt="" width="753" height="447"></p>
<h1>MongoDB安装</h1>
<p>  本来想写的,相应的文章在园子太多了,借用一位仁兄的博文,传送门</p>
<p>  MongoDB下载地址:https://www.mongodb.com/download-center#community</p>
<p>  管理工具:Robomongo,传送门</p>
<h1>MongoDB.Driver的使用</h1>
<p>  <img src="https://images2015.cnblogs.com/blog/488722/201703/488722-20170322163723986-71226610.png" alt="" width="530" height="377"></p>
<p>  创建一个控制台,到Nuget下载MongoDB.Driver。写入以下代码:</p>
<div class="cnblogs_code"><img id="code_img_closed_ab403584-ccc0-41c9-bd5d-7d526f026c1f" class="code_img_closed" src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" alt=""><img id="code_img_opened_ab403584-ccc0-41c9-bd5d-7d526f026c1f" class="code_img_opened" style="display: none" src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" alt="">
<div id="cnblogs_code_open_ab403584-ccc0-41c9-bd5d-7d526f026c1f" class="cnblogs_code_hide">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span> <span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> System;
</span><span style="color: rgba(0, 128, 128, 1)"> 2</span> <span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> FrameWork.MongoDB.MongoDbConfig;
</span><span style="color: rgba(0, 128, 128, 1)"> 3</span> <span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> MongoDB.Bson.Serialization.Attributes;
</span><span style="color: rgba(0, 128, 128, 1)"> 4</span> <span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> MongoDB.Driver;
</span><span style="color: rgba(0, 128, 128, 1)"> 5</span>
<span style="color: rgba(0, 128, 128, 1)"> 6</span> <span style="color: rgba(0, 0, 255, 1)">namespace</span><span style="color: rgba(0, 0, 0, 1)"> FrameWork.MongoDb.Demo
</span><span style="color: rgba(0, 128, 128, 1)"> 7</span> <span style="color: rgba(0, 0, 0, 1)">{
</span><span style="color: rgba(0, 128, 128, 1)"> 8</span>   <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> Program
</span><span style="color: rgba(0, 128, 128, 1)"> 9</span> <span style="color: rgba(0, 0, 0, 1)">    {
</span><span style="color: rgba(0, 128, 128, 1)">10</span>         <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span> Main(<span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)">[] args)
</span><span style="color: rgba(0, 128, 128, 1)">11</span> <span style="color: rgba(0, 0, 0, 1)">      {
</span><span style="color: rgba(0, 128, 128, 1)">12</span>             <span style="color: rgba(0, 0, 255, 1)">var</span> database = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">testdatabase</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">13</span>             <span style="color: rgba(0, 0, 255, 1)">var</span> collection = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">TestMongo</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">14</span>             <span style="color: rgba(0, 0, 255, 1)">var</span> db = <span style="color: rgba(0, 0, 255, 1)">new</span> MongoClient(<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)">"</span><span style="color: rgba(0, 0, 0, 1)">).GetDatabase(database);
</span><span style="color: rgba(0, 128, 128, 1)">15</span>             <span style="color: rgba(0, 0, 255, 1)">var</span> coll = db.GetCollection&lt;TestMongo&gt;<span style="color: rgba(0, 0, 0, 1)">(collection);
</span><span style="color: rgba(0, 128, 128, 1)">16</span>
<span style="color: rgba(0, 128, 128, 1)">17</span>             <span style="color: rgba(0, 0, 255, 1)">var</span> entity = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> TestMongo
</span><span style="color: rgba(0, 128, 128, 1)">18</span> <span style="color: rgba(0, 0, 0, 1)">            {
</span><span style="color: rgba(0, 128, 128, 1)">19</span>               Name = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">SkyChen</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 128, 1)">20</span>               Amount = <span style="color: rgba(128, 0, 128, 1)">100</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 128, 1)">21</span>               CreateDateTime =<span style="color: rgba(0, 0, 0, 1)"> DateTime.Now
</span><span style="color: rgba(0, 128, 128, 1)">22</span> <span style="color: rgba(0, 0, 0, 1)">            };
</span><span style="color: rgba(0, 128, 128, 1)">23</span>
<span style="color: rgba(0, 128, 128, 1)">24</span>             coll.InsertOneAsync(entity).ConfigureAwait(<span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">25</span>
<span style="color: rgba(0, 128, 128, 1)">26</span> <span style="color: rgba(0, 0, 0, 1)">      }
</span><span style="color: rgba(0, 128, 128, 1)">27</span> <span style="color: rgba(0, 0, 0, 1)">    }
</span><span style="color: rgba(0, 128, 128, 1)">28</span>
<span style="color: rgba(0, 128, 128, 1)">29</span>   <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> TestMongo : MongoEntity
</span><span style="color: rgba(0, 128, 128, 1)">30</span> <span style="color: rgba(0, 0, 0, 1)">    {
</span><span style="color: rgba(0, 128, 128, 1)">31</span>
<span style="color: rgba(0, 128, 128, 1)">32</span>         
</span><span style="color: rgba(0, 128, 128, 1)">33</span>         <span style="color: rgba(0, 0, 255, 1)">public</span> DateTime CreateDateTime { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
</span><span style="color: rgba(0, 128, 128, 1)">34</span>
<span style="color: rgba(0, 128, 128, 1)">35</span>         <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">decimal</span> Amount { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
</span><span style="color: rgba(0, 128, 128, 1)">36</span>
<span style="color: rgba(0, 128, 128, 1)">37</span>         <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span> Name { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
</span><span style="color: rgba(0, 128, 128, 1)">38</span>
<span style="color: rgba(0, 128, 128, 1)">39</span> <span style="color: rgba(0, 0, 0, 1)">    }
</span><span style="color: rgba(0, 128, 128, 1)">40</span> }</pre>
</div>
<span class="cnblogs_code_collapse">View Code</span></div>
<p>  第一个demo:添加数据就完成了。F12可以看到IMongoCollection这个接口,增删改查都有,注意分One和Many。基础的使用就不扯过多,在文章尾部的代码已经提供增删改查的封装。</p>
<p>  增删查的封装相对简单,但是MongoDB.Driver提供的update的稍微比较特殊。通过Builders&lt;T&gt;.Update.Set(_fieldname, value)更新指定字段名,有多个字段名需要修改,就要通过new UpdateDefinitionBuilder&lt;T&gt;().Combine(updateDefinitionList)去完成</p>
<p><img src="https://images2015.cnblogs.com/blog/488722/201703/488722-20170322174909518-1654524019.png" alt="" width="581" height="178"></p>
<p>  然而,这种方式并不适用于我们实际开发,因此需要对Update方法进行 <strong>实体更新封装</strong>和<strong>Lambda更新封装</strong>。</p>
<h1>实体更新封装</h1>
<p>  通过ID作为过滤条件更新整个实体在实际工作中是常有的。既然通过ID作为条件,那么只能通过UpdateOneAsync进行约束更新一条数据。更新的字段可以通过反射实体对象进行遍历属性。下边是实现代码:</p>
<div class="cnblogs_code"><img id="code_img_closed_a43eb10b-ab0d-49e8-8255-64662456f21c" class="code_img_closed" src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" alt=""><img id="code_img_opened_a43eb10b-ab0d-49e8-8255-64662456f21c" class="code_img_opened" style="display: none" src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" alt="">
<div id="cnblogs_code_open_a43eb10b-ab0d-49e8-8255-64662456f21c" class="cnblogs_code_hide">
<pre><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;summary&gt;</span>
    <span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> mongodb扩展方法
    </span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;/summary&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">internal</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> MongoDbExtension
    {
      </span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;summary&gt;</span>
      <span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 获取更新信息
      </span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;/summary&gt;</span>
      <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;typeparam name="T"&gt;&lt;/typeparam&gt;</span>
      <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;param name="entity"&gt;&lt;/param&gt;</span>
      <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;returns&gt;&lt;/returns&gt;</span>
      <span style="color: rgba(0, 0, 255, 1)">internal</span> <span style="color: rgba(0, 0, 255, 1)">static</span> UpdateDefinition&lt;T&gt; GetUpdateDefinition&lt;T&gt;(<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)"> T entity)
      {
            </span><span style="color: rgba(0, 0, 255, 1)">var</span> properties = <span style="color: rgba(0, 0, 255, 1)">typeof</span>(T).GetProperties(BindingFlags.Instance |<span style="color: rgba(0, 0, 0, 1)"> BindingFlags.Public);

            </span><span style="color: rgba(0, 0, 255, 1)">var</span> updateDefinitionList = GetUpdateDefinitionList&lt;T&gt;<span style="color: rgba(0, 0, 0, 1)">(properties, entity);

            </span><span style="color: rgba(0, 0, 255, 1)">var</span> updateDefinitionBuilder = <span style="color: rgba(0, 0, 255, 1)">new</span> UpdateDefinitionBuilder&lt;T&gt;<span style="color: rgba(0, 0, 0, 1)">().Combine(updateDefinitionList);

            </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> updateDefinitionBuilder;
      }

      </span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;summary&gt;</span>
      <span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 获取更新信息
      </span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;/summary&gt;</span>
      <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;typeparam name="T"&gt;&lt;/typeparam&gt;</span>
      <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;param name="propertyInfos"&gt;&lt;/param&gt;</span>
      <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;param name="entity"&gt;&lt;/param&gt;</span>
      <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;returns&gt;&lt;/returns&gt;</span>
      <span style="color: rgba(0, 0, 255, 1)">internal</span> <span style="color: rgba(0, 0, 255, 1)">static</span> List&lt;UpdateDefinition&lt;T&gt;&gt; GetUpdateDefinitionList&lt;T&gt;(PropertyInfo[] propertyInfos, <span style="color: rgba(0, 0, 255, 1)">object</span><span style="color: rgba(0, 0, 0, 1)"> entity)
      {
            </span><span style="color: rgba(0, 0, 255, 1)">var</span> updateDefinitionList = <span style="color: rgba(0, 0, 255, 1)">new</span> List&lt;UpdateDefinition&lt;T&gt;&gt;<span style="color: rgba(0, 0, 0, 1)">();

            propertyInfos </span>= propertyInfos.Where(a =&gt; a.Name != <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)">).ToArray();

            </span><span style="color: rgba(0, 0, 255, 1)">foreach</span> (<span style="color: rgba(0, 0, 255, 1)">var</span> propertyInfo <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> propertyInfos)
            {
                </span><span style="color: rgba(0, 0, 255, 1)">if</span> (propertyInfo.PropertyType.IsArray || <span style="color: rgba(0, 0, 255, 1)">typeof</span><span style="color: rgba(0, 0, 0, 1)">(IList).IsAssignableFrom(propertyInfo.PropertyType))
                {
                  </span><span style="color: rgba(0, 0, 255, 1)">var</span> value = propertyInfo.GetValue(entity) <span style="color: rgba(0, 0, 255, 1)">as</span><span style="color: rgba(0, 0, 0, 1)"> IList;

                  </span><span style="color: rgba(0, 0, 255, 1)">var</span> filedName =<span style="color: rgba(0, 0, 0, 1)"> propertyInfo.Name;

                  updateDefinitionList.Add(Builders</span>&lt;T&gt;<span style="color: rgba(0, 0, 0, 1)">.Update.Set(filedName, value));
                }
                </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)">
                {
                  </span><span style="color: rgba(0, 0, 255, 1)">var</span> value =<span style="color: rgba(0, 0, 0, 1)"> propertyInfo.GetValue(entity);
                  </span><span style="color: rgba(0, 0, 255, 1)">if</span> (propertyInfo.PropertyType == <span style="color: rgba(0, 0, 255, 1)">typeof</span>(<span style="color: rgba(0, 0, 255, 1)">decimal</span><span style="color: rgba(0, 0, 0, 1)">))
                        value </span>=<span style="color: rgba(0, 0, 0, 1)"> value.ToString();

                  </span><span style="color: rgba(0, 0, 255, 1)">var</span> filedName =<span style="color: rgba(0, 0, 0, 1)"> propertyInfo.Name;

                  updateDefinitionList.Add(Builders</span>&lt;T&gt;<span style="color: rgba(0, 0, 0, 1)">.Update.Set(filedName, value));
                }
            }

            </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> updateDefinitionList;
      }
    }</span></pre>
</div>
<span class="cnblogs_code_collapse">View Code</span></div>
<p>&nbsp;</p>
<h1>Lambda表达式更新封装</h1>
<p>  曾经用过其他ORM都清楚Lambda表达式使用是非常频繁的,MongoDB.Driver已经支持Lambda表达式的过滤条件,但没支持部分字段更新,因此由我们自己来写解析。下边是现实代码:</p>
<div class="cnblogs_code"><img id="code_img_closed_318509fe-b0a9-49de-8c73-c770b5dbcadc" class="code_img_closed" src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" alt=""><img id="code_img_opened_318509fe-b0a9-49de-8c73-c770b5dbcadc" class="code_img_opened" style="display: none" src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" alt="">
<div id="cnblogs_code_open_318509fe-b0a9-49de-8c73-c770b5dbcadc" class="cnblogs_code_hide">
<pre><span style="color: rgba(0, 0, 255, 1)">#region</span> Mongo更新字段表达式解析
    <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;summary&gt;</span>
    <span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> Mongo更新字段表达式解析
    </span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;/summary&gt;</span>
    <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;typeparam name="T"&gt;&lt;/typeparam&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span> MongoDbExpression&lt;T&gt;<span style="color: rgba(0, 0, 0, 1)"> : ExpressionVisitor
    {
      </span><span style="color: rgba(0, 0, 255, 1)">#region</span> 成员变量
      <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;summary&gt;</span>
      <span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 更新列表
      </span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;/summary&gt;</span>
      <span style="color: rgba(0, 0, 255, 1)">internal</span> List&lt;UpdateDefinition&lt;T&gt;&gt; UpdateDefinitionList = <span style="color: rgba(0, 0, 255, 1)">new</span> List&lt;UpdateDefinition&lt;T&gt;&gt;<span style="color: rgba(0, 0, 0, 1)">();
      </span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)"> _fieldname;

      </span><span style="color: rgba(0, 0, 255, 1)">#endregion</span>

      <span style="color: rgba(0, 0, 255, 1)">#region</span> 获取更新列表
      <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;summary&gt;</span>
      <span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 获取更新列表
      </span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;/summary&gt;</span>
      <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;param name="expression"&gt;&lt;/param&gt;</span>
      <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;returns&gt;&lt;/returns&gt;</span>
      <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> List&lt;UpdateDefinition&lt;T&gt;&gt; GetUpdateDefinition(Expression&lt;Func&lt;T, T&gt;&gt;<span style="color: rgba(0, 0, 0, 1)"> expression)
      {
            </span><span style="color: rgba(0, 0, 255, 1)">var</span> mongoDb = <span style="color: rgba(0, 0, 255, 1)">new</span> MongoDbExpression&lt;T&gt;<span style="color: rgba(0, 0, 0, 1)">();

            mongoDb.Resolve(expression);
            </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> mongoDb.UpdateDefinitionList;
      }
      </span><span style="color: rgba(0, 0, 255, 1)">#endregion</span>

      <span style="color: rgba(0, 0, 255, 1)">#region</span> 解析表达式
      <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;summary&gt;</span>
      <span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 解析表达式
      </span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;/summary&gt;</span>
      <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;param name="expression"&gt;&lt;/param&gt;</span>
      <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">void</span> Resolve(Expression&lt;Func&lt;T, T&gt;&gt;<span style="color: rgba(0, 0, 0, 1)"> expression)
      {
            Visit(expression);
      }
      </span><span style="color: rgba(0, 0, 255, 1)">#endregion</span>

      <span style="color: rgba(0, 0, 255, 1)">#region</span> 访问对象初始化表达式

      <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;summary&gt;</span>
      <span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 访问对象初始化表达式
      </span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;/summary&gt;</span>
      <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;param name="node"&gt;&lt;/param&gt;</span>
      <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;returns&gt;&lt;/returns&gt;</span>
      <span style="color: rgba(0, 0, 255, 1)">protected</span> <span style="color: rgba(0, 0, 255, 1)">override</span><span style="color: rgba(0, 0, 0, 1)"> Expression VisitMemberInit(MemberInitExpression node)
      {
            </span><span style="color: rgba(0, 0, 255, 1)">var</span> bingdings =<span style="color: rgba(0, 0, 0, 1)"> node.Bindings;

            </span><span style="color: rgba(0, 0, 255, 1)">foreach</span> (<span style="color: rgba(0, 0, 255, 1)">var</span> item <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> bingdings)
            {
                </span><span style="color: rgba(0, 0, 255, 1)">var</span> memberAssignment =<span style="color: rgba(0, 0, 0, 1)"> (MemberAssignment)item;
                _fieldname </span>=<span style="color: rgba(0, 0, 0, 1)"> item.Member.Name;

                </span><span style="color: rgba(0, 0, 255, 1)">if</span> (memberAssignment.Expression.NodeType ==<span style="color: rgba(0, 0, 0, 1)"> ExpressionType.MemberInit)
                {
                  </span><span style="color: rgba(0, 0, 255, 1)">var</span> lambda = Expression.Lambda&lt;Func&lt;<span style="color: rgba(0, 0, 255, 1)">object</span>&gt;&gt;(Expression.Convert(memberAssignment.Expression, <span style="color: rgba(0, 0, 255, 1)">typeof</span>(<span style="color: rgba(0, 0, 255, 1)">object</span><span style="color: rgba(0, 0, 0, 1)">)));
                  </span><span style="color: rgba(0, 0, 255, 1)">var</span> value =<span style="color: rgba(0, 0, 0, 1)"> lambda.Compile().Invoke();
                  UpdateDefinitionList.Add(Builders</span>&lt;T&gt;<span style="color: rgba(0, 0, 0, 1)">.Update.Set(_fieldname, value));
                }
                </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)">
                {
                  Visit(memberAssignment.Expression);
                }
            }
            </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> node;
      }

      </span><span style="color: rgba(0, 0, 255, 1)">#endregion</span>

      <span style="color: rgba(0, 0, 255, 1)">#region</span> 访问二元表达式

      <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;summary&gt;</span>
      <span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 访问二元表达式
      </span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;/summary&gt;</span>
      <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;param name="node"&gt;&lt;/param&gt;</span>
      <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;returns&gt;&lt;/returns&gt;</span>
      <span style="color: rgba(0, 0, 255, 1)">protected</span> <span style="color: rgba(0, 0, 255, 1)">override</span><span style="color: rgba(0, 0, 0, 1)"> Expression VisitBinary(BinaryExpression node)
      {
            UpdateDefinition</span>&lt;T&gt;<span style="color: rgba(0, 0, 0, 1)"> updateDefinition;

            </span><span style="color: rgba(0, 0, 255, 1)">var</span> value =<span style="color: rgba(0, 0, 0, 1)"> ((ConstantExpression)node.Right).Value;
            </span><span style="color: rgba(0, 0, 255, 1)">if</span> (node.Type == <span style="color: rgba(0, 0, 255, 1)">typeof</span>(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)">))
            {
                </span><span style="color: rgba(0, 0, 255, 1)">var</span> realValue = (<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)">)value;
                </span><span style="color: rgba(0, 0, 255, 1)">if</span> (node.NodeType ==<span style="color: rgba(0, 0, 0, 1)"> ExpressionType.Decrement)
                  realValue </span>= -<span style="color: rgba(0, 0, 0, 1)">realValue;

                updateDefinition </span>= Builders&lt;T&gt;<span style="color: rgba(0, 0, 0, 1)">.Update.Inc(_fieldname, realValue);
            }
            </span><span style="color: rgba(0, 0, 255, 1)">else</span> <span style="color: rgba(0, 0, 255, 1)">if</span> (node.Type == <span style="color: rgba(0, 0, 255, 1)">typeof</span>(<span style="color: rgba(0, 0, 255, 1)">long</span><span style="color: rgba(0, 0, 0, 1)">))
            {
                </span><span style="color: rgba(0, 0, 255, 1)">var</span> realValue = (<span style="color: rgba(0, 0, 255, 1)">long</span><span style="color: rgba(0, 0, 0, 1)">)value;
                </span><span style="color: rgba(0, 0, 255, 1)">if</span> (node.NodeType ==<span style="color: rgba(0, 0, 0, 1)"> ExpressionType.Decrement)
                  realValue </span>= -<span style="color: rgba(0, 0, 0, 1)">realValue;

                updateDefinition </span>= Builders&lt;T&gt;<span style="color: rgba(0, 0, 0, 1)">.Update.Inc(_fieldname, realValue);
            }
            </span><span style="color: rgba(0, 0, 255, 1)">else</span> <span style="color: rgba(0, 0, 255, 1)">if</span> (node.Type == <span style="color: rgba(0, 0, 255, 1)">typeof</span>(<span style="color: rgba(0, 0, 255, 1)">double</span><span style="color: rgba(0, 0, 0, 1)">))
            {
                </span><span style="color: rgba(0, 0, 255, 1)">var</span> realValue = (<span style="color: rgba(0, 0, 255, 1)">double</span><span style="color: rgba(0, 0, 0, 1)">)value;
                </span><span style="color: rgba(0, 0, 255, 1)">if</span> (node.NodeType ==<span style="color: rgba(0, 0, 0, 1)"> ExpressionType.Decrement)
                  realValue </span>= -<span style="color: rgba(0, 0, 0, 1)">realValue;

                updateDefinition </span>= Builders&lt;T&gt;<span style="color: rgba(0, 0, 0, 1)">.Update.Inc(_fieldname, realValue);
            }
            </span><span style="color: rgba(0, 0, 255, 1)">else</span> <span style="color: rgba(0, 0, 255, 1)">if</span> (node.Type == <span style="color: rgba(0, 0, 255, 1)">typeof</span>(<span style="color: rgba(0, 0, 255, 1)">decimal</span><span style="color: rgba(0, 0, 0, 1)">))
            {
                </span><span style="color: rgba(0, 0, 255, 1)">var</span> realValue = (<span style="color: rgba(0, 0, 255, 1)">decimal</span><span style="color: rgba(0, 0, 0, 1)">)value;
                </span><span style="color: rgba(0, 0, 255, 1)">if</span> (node.NodeType ==<span style="color: rgba(0, 0, 0, 1)"> ExpressionType.Decrement)
                  realValue </span>= -<span style="color: rgba(0, 0, 0, 1)">realValue;

                updateDefinition </span>= Builders&lt;T&gt;<span style="color: rgba(0, 0, 0, 1)">.Update.Inc(_fieldname, realValue);
            }
            </span><span style="color: rgba(0, 0, 255, 1)">else</span> <span style="color: rgba(0, 0, 255, 1)">if</span> (node.Type == <span style="color: rgba(0, 0, 255, 1)">typeof</span>(<span style="color: rgba(0, 0, 255, 1)">float</span><span style="color: rgba(0, 0, 0, 1)">))
            {
                </span><span style="color: rgba(0, 0, 255, 1)">var</span> realValue = (<span style="color: rgba(0, 0, 255, 1)">float</span><span style="color: rgba(0, 0, 0, 1)">)value;
                </span><span style="color: rgba(0, 0, 255, 1)">if</span> (node.NodeType ==<span style="color: rgba(0, 0, 0, 1)"> ExpressionType.Decrement)
                  realValue </span>= -<span style="color: rgba(0, 0, 0, 1)">realValue;

                updateDefinition </span>= Builders&lt;T&gt;<span style="color: rgba(0, 0, 0, 1)">.Update.Inc(_fieldname, realValue);
            }
            </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)">
            {
                </span><span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span> Exception(_fieldname + <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)">"</span><span style="color: rgba(0, 0, 0, 1)">);
            }

            UpdateDefinitionList.Add(updateDefinition);

            </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> node;
      }
      </span><span style="color: rgba(0, 0, 255, 1)">#endregion</span>

      <span style="color: rgba(0, 0, 255, 1)">#region</span> 访问数组表达式

      <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;summary&gt;</span>
      <span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 访问数组表达式
      </span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;/summary&gt;</span>
      <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;param name="node"&gt;&lt;/param&gt;</span>
      <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;returns&gt;&lt;/returns&gt;</span>
      <span style="color: rgba(0, 0, 255, 1)">protected</span> <span style="color: rgba(0, 0, 255, 1)">override</span><span style="color: rgba(0, 0, 0, 1)"> Expression VisitNewArray(NewArrayExpression node)
      {
            </span><span style="color: rgba(0, 0, 255, 1)">var</span> listLambda = Expression.Lambda&lt;Func&lt;IList&gt;&gt;<span style="color: rgba(0, 0, 0, 1)">(node);
            </span><span style="color: rgba(0, 0, 255, 1)">var</span> list =<span style="color: rgba(0, 0, 0, 1)"> listLambda.Compile().Invoke();
            UpdateDefinitionList.Add(Builders</span>&lt;T&gt;<span style="color: rgba(0, 0, 0, 1)">.Update.Set(_fieldname, list));

            </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> node;
      }

      </span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;summary&gt;</span>
      <span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 访问集合表达式
      </span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;/summary&gt;</span>
      <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;param name="node"&gt;&lt;/param&gt;</span>
      <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;returns&gt;&lt;/returns&gt;</span>
      <span style="color: rgba(0, 0, 255, 1)">protected</span> <span style="color: rgba(0, 0, 255, 1)">override</span><span style="color: rgba(0, 0, 0, 1)"> Expression VisitListInit(ListInitExpression node)
      {
            </span><span style="color: rgba(0, 0, 255, 1)">var</span> listLambda = Expression.Lambda&lt;Func&lt;IList&gt;&gt;<span style="color: rgba(0, 0, 0, 1)">(node);
            </span><span style="color: rgba(0, 0, 255, 1)">var</span> list =<span style="color: rgba(0, 0, 0, 1)"> listLambda.Compile().Invoke();
            UpdateDefinitionList.Add(Builders</span>&lt;T&gt;<span style="color: rgba(0, 0, 0, 1)">.Update.Set(_fieldname, list));

            </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> node;
      }
      </span><span style="color: rgba(0, 0, 255, 1)">#endregion</span>

      <span style="color: rgba(0, 0, 255, 1)">#region</span> 访问常量表达式

      <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;summary&gt;</span>
      <span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 访问常量表达式
      </span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;/summary&gt;</span>
      <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;param name="node"&gt;&lt;/param&gt;</span>
      <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;returns&gt;&lt;/returns&gt;</span>
      <span style="color: rgba(0, 0, 255, 1)">protected</span> <span style="color: rgba(0, 0, 255, 1)">override</span><span style="color: rgba(0, 0, 0, 1)"> Expression VisitConstant(ConstantExpression node)
      {
            </span><span style="color: rgba(0, 0, 255, 1)">var</span> value = node.Type.IsEnum ? (<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)">)node.Value : node.Value;

            UpdateDefinitionList.Add(Builders</span>&lt;T&gt;<span style="color: rgba(0, 0, 0, 1)">.Update.Set(_fieldname, value));

            </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> node;
      }
      </span><span style="color: rgba(0, 0, 255, 1)">#endregion</span>

      <span style="color: rgba(0, 0, 255, 1)">#region</span> 访问成员表达式

      <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;summary&gt;</span>
      <span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 访问成员表达式
      </span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;/summary&gt;</span>
      <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;param name="node"&gt;&lt;/param&gt;</span>
      <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;returns&gt;&lt;/returns&gt;</span>
      <span style="color: rgba(0, 0, 255, 1)">protected</span> <span style="color: rgba(0, 0, 255, 1)">override</span><span style="color: rgba(0, 0, 0, 1)"> Expression VisitMember(MemberExpression node)
      {
            </span><span style="color: rgba(0, 0, 255, 1)">if</span> (node.Type.GetInterfaces().Any(a =&gt; a.Name == <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">IList</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> lambda = Expression.Lambda&lt;Func&lt;IList&gt;&gt;<span style="color: rgba(0, 0, 0, 1)">(node);
                </span><span style="color: rgba(0, 0, 255, 1)">var</span> value =<span style="color: rgba(0, 0, 0, 1)"> lambda.Compile().Invoke();

                UpdateDefinitionList.Add(Builders</span>&lt;T&gt;<span style="color: rgba(0, 0, 0, 1)">.Update.Set(_fieldname, value));
            }
            </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)">
            {
                </span><span style="color: rgba(0, 0, 255, 1)">var</span> lambda = Expression.Lambda&lt;Func&lt;<span style="color: rgba(0, 0, 255, 1)">object</span>&gt;&gt;(Expression.Convert(node, <span style="color: rgba(0, 0, 255, 1)">typeof</span>(<span style="color: rgba(0, 0, 255, 1)">object</span><span style="color: rgba(0, 0, 0, 1)">)));
                </span><span style="color: rgba(0, 0, 255, 1)">var</span> value =<span style="color: rgba(0, 0, 0, 1)"> lambda.Compile().Invoke();

                </span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (node.Type.IsEnum)
                  value </span>= (<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)">)value;

                UpdateDefinitionList.Add(Builders</span>&lt;T&gt;<span style="color: rgba(0, 0, 0, 1)">.Update.Set(_fieldname, value));
            }

            </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> node;
      }
      </span><span style="color: rgba(0, 0, 255, 1)">#endregion</span><span style="color: rgba(0, 0, 0, 1)">
    }
    </span><span style="color: rgba(0, 0, 255, 1)">#endregion</span></pre>
</div>
<span class="cnblogs_code_collapse">View Code</span></div>
<p>&nbsp;</p>
<h1>表达式树的解析</h1>
<p>  对于Lambda表达式的封装,我侧重讲一下。假如有一段这样的更新代码:  </p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">new</span> MongoDbService().Update&lt;User&gt;(a =&gt; a._id == <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">d99ce40d7a0b49768b74735b91f2aa75</span><span style="color: rgba(128, 0, 0, 1)">"</span>, a =&gt; <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> User
            {
                AddressList </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> List&lt;<span style="color: rgba(0, 0, 255, 1)">string</span>&gt;<span style="color: rgba(0, 0, 0, 1)">
                {
                  </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">number1</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
                  </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">number2</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
                },
                Age </span>= <span style="color: rgba(128, 0, 128, 1)">10</span><span style="color: rgba(0, 0, 0, 1)">,
                BirthDateTime </span>=<span style="color: rgba(0, 0, 0, 1)"> DateTime.Now,
                Name </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">skychen</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
                NumList </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> List&lt;<span style="color: rgba(0, 0, 255, 1)">int</span>&gt;<span style="color: rgba(0, 0, 0, 1)">
                {
                  </span><span style="color: rgba(128, 0, 128, 1)">1211</span>,<span style="color: rgba(128, 0, 128, 1)">23344</span><span style="color: rgba(0, 0, 0, 1)">
                },
                Sex </span>=<span style="color: rgba(0, 0, 0, 1)"> Sex.Woman,
                Son </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> User
                {
                  Name </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">xiaochenpi</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
                  Age </span>= <span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">
                }
            });</span></pre>
</div>
<p>  那么,我们可以调试监视看看(下图),我们可以得出两个重要信息:</p>
<p>  1.Expression&lt;Func&lt;T, T&gt;&gt;解析出来Body的NodeType是MemberInit</p>
<p>  2.Bindings里有需要修改的字段信息。</p>
<p><img src="https://images2015.cnblogs.com/blog/488722/201703/488722-20170322180800549-1531001302.png" alt="" width="524" height="275"></p>
<p><img src="https://images2015.cnblogs.com/blog/488722/201703/488722-20170322222345580-1804167075.png" alt="" width="524" height="274"></p>
<p>  再调试进去看看Bindings的第一项,我们又可以了解了几个重要信息。</p>
<p>  1.Bindings里的元素是MemberAssignment类型。</p>
<p>  2.Member能取到Name属性,也就是字段名</p>
<p>  3.Expression属性,使用 Expression.Lambda,进行Compile().Invoke()就能得到我们需要的值。</p>
<p>  fileName和Value都能取到了,那么更新自然能解决了。</p>
<p><img src="https://images2015.cnblogs.com/blog/488722/201703/488722-20170323093738315-1811986504.jpg" alt="" width="904" height="508"></p>
<p>  上图是源码的部分核心代码,奇怪的是,我并没有在VisitMemberInit里进行遍历Bindings后进行Update.Set,而是将item的Expression属性再一次访问。那是因为我需要针对不同的数据类型进行处理。例如:</p>
<p>  常量,我可以定义一个object value进行去接收,如果遇到枚举我需要强转成整型。</p>
<p>  集合与数组,假如草率的使用object类型,object value =&nbsp;Expression.Lambda&lt;Func&lt;object&gt;&gt;(node).Compile().Invoke(),那么更新到MongoDB里就会有bug,奇怪的_t,_v就会出现。以此我需要定义为IList才能解决这个问题。</p>
<p>  此外,工作中还会遇到金额或者数量自增的情况。Amount = a.Amount+9.9M,Count =a.Count-1。&nbsp;MongoDB.Driver提供了Builders&lt;T&gt;.Update.Inc方法,因此重写二元表达式进行封装。</p>
<p><img src="https://images2015.cnblogs.com/blog/488722/201703/488722-20170322224641158-412607837.png" alt="" width="553" height="472"></p>
<h1>附加</h1>
<p>  经过测试,官方驱动2.4.3和2.4.4版本对类型IList支持有问题,如下图,所以现在封装版本最高支持到2.4.2。</p>
<p>  <img src="https://images2015.cnblogs.com/blog/488722/201706/488722-20170613115302915-1815703319.jpg" alt="" width="595" height="438"><img src="https://images2015.cnblogs.com/blog/488722/201706/488722-20170613115314212-1837672851.png" alt=""></p>
<h1>结束</h1>
<p>  不知道有多少朋友直接拖到文章尾部直接下载源码的。。。。。。</p>
<p>  如果对您有用,麻烦您推荐一下。</p>
<p>  此外还要感谢非非大哥哥,率先做了我的小白鼠给我提出了可贵的BUG,不然我还真不敢放出源码。</p>
<p>  如果有什么问题和建议,可以在下方评论,我会及时回复。</p>
<p>  双手奉上源码:https://github.com/SkyChenSky/Framework.MongoDB.git</p>

</div>
<div id="MySignature" role="contentinfo">
    <div style="display: block; background: #406CA4;" id="my_signature">
<p style="padding-right: 10px; padding-bottom: 10px; padding-left: 20px; font-family: 微软雅黑; font-size: 12px; border: #e0e0e0 1px dashed; color: white;">
<br>作  者:<strong><span style="font-size: 12px">
陈珙 </span></strong> <br>
      出  处:http://www.cnblogs.com/skychen1218/
      <br>
      关于作者:专注于微软平台的项目开发。如有问题或建议,请多多赐教!
      <br>
      版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。
      <br>
      声援博主:如果您觉得文章对您有帮助,可以点击文章右下角<strong style="color: red">推荐</strong>一下。您的鼓励是作者坚持原创和持续写作的最大动力!
      <br>
    </p>
</div><br><br>
来源:https://www.cnblogs.com/skychen1218/p/6595759.html
頁: [1]
查看完整版本: .net平台的MongoDB使用