【原创】打造基于Dapper的数据访问层

 
  • 前言

  闲来无事,花几天功夫将之前项目里用到的一个数据访问层整理了出来。实现单个实体的增删改查,可执行存储过程,可输出返回参数,查询结果集可根据实际情况返回DataTable、DataSet和强类型,同时支持不同类型数据库。目前成熟的ORM框架多不胜数,再写一个出来,并非想证明自己写的有多好,一来认为现有成熟的ORM框架并不能灵活适用于大型ERP项目,二来有感于工作多年有必要写下一些东西。虽然有种重复造轮子的感觉,但相信朋友们和我一样,享受造轮子的过程并把它当成一种乐趣,对吧。

  • 调用示例

  1、LinQ 语法查询

1     //LinQ 语法查询
2     query = rptBase.Query<Bas_Company>();
3     query = rptBase.Query<Bas_Company>(x => true);
4     query = rptBase.Query<Bas_Company>(x => true && (x.CompanyID ?? null) != null && new[] { "1", "2" }.Contains(x.CompanyID) &&
5         x.CompanyID.Substring(2, 5).TrimEnd() == "OK" && x.AllowUsed);

  2、分页查询

1     //分页查询
2     query = rptBase.Query<Bas_Company>(new PageInfo(3, 20));
3     query = rptBase.Query<Bas_Company>(new PageInfo(3, 20), x => x.CompanyID == "FT");

  3、自定义脚本查询

1     d = new DynamicParameters();
2     d.Add("CompanyName", "美之源科技有限公司", DbType.String, null, 20);
3     query = rptBase.Query<Bas_Company>("Select * From Bas_Company WHERE CompanyName = @CompanyName", d);

  4、自定义参数查询

1     //自定义参数查询
2     d = new DynamicParameters();
3     d.Add("CompanyName", "美之源科技有限公司");
4     query = rptBase.Query<Bas_Company>("selectByName", null, d);

  5、带返回值查询

1     //带返回值查询
2     d = new DynamicParameters();
3     d.Add("Row", null);
4     table = rptBase.QueryDataTable<Bas_Company>("returnValue", x => x.CompanyID != "FT", d);
5     eff = d.Get<int?>("Row");

  6、自定义实体查询

1     //查询自定义实体
2     var query1 = rptBase.Query<ThinEntity>(typeof(Bas_Company).FullName, "thinEntity", "And CompanyID <> 'FT' ");

  7、DataTable 查询

1     DataTable table = null;
2     table = rptBase.QueryDataTable<Bas_Company>();
3     table = rptBase.QueryDataTable<Bas_Company>(x => true);

  8、DataSet 查询

1     DataSet data = null;
2     data = rptBase.QueryDataSet<Bas_Company>("Select",x => true);

  9、增删改

 1     //新增
 2     Bas_Company company = new Bas_Company();
 3     company.CompanyID = "TH";
 4     company.CompanyCode = "TH001";
 5     rptBase.Insert(company);
 6
 7     //修改
 8     company.CompanyCode = "TH00x";
 9     rptBase.Update(company);
10     //批量修改
11     rptBase.Update<Bas_Company>(x => new Bas_Company { CompanyCode = "TH003" }, x => x.CompanyID == "TH");
12
13     //删除
14     rptBase.Delete(company);

  10、解析成字符串

1     sql = rptBase.Resolve<Bas_Company>("Select",x => true && (x.CompanyID ?? null) != null && new[] { "1", "2" }.Contains(x.CompanyID) &&
2         x.CompanyID.Substring(2, 5).TrimEnd() == "OK" && x.AllowUsed);
3     sqlList.Add(sql);

  还有其它的重载这里就不一一列举,源代码的单元测试里有很详细的说明。

  • 详细解析

  先来看看项目架构截图:

03.Src:第三方开源组件源码,有的目前没有用到,先收藏着;
04.Infrastructure:整个项目公用类库,包含一些Helper和公用类;
05.DataAccess:数据访问核心类库,实现Lambda表达式解析、Dapper封装等;
06.Model:实体层,实体使用CodeSmith生成,包含实体和脚本映射两个部分;
09.Presentation:展示层,目前只有一个单元测试项目。

  Dapper,一个基于IDbConnection扩展的完全开源的轻、小、快的ORM框架(项目源码 https://github.com/SamSaffron/dapper-dot-net )。在本框架中,需要解决的主要问题有如下几点:

  1. 如何生成Dapper查询所需要的TSQL脚本和参数
  2. 如何将Lambda表达式解析成查询条件
  3. 如何将Dapper返回的IDataReader转化成DataTable和DataSet
  4. 如何解决多数据库的问题

--------------------------------------- 华丽丽的分割线 --------------------------------------------

  1. 如何生成Dapper查询所需要的SQL语句和参数

  基于SQL和代码分离原则,数据库中每一张表都有一个POCO实体与之对应并且用一个Xml文件来描述,包括表名称、字段、主键和增删改查SQL及参数。因为Xml文件的结构都是一样的,我这里用CodeSmith Studio来自动生成。CodeSmith的语法跟Asp.Net的语法类似,这里 http://blog.csdn.net/mapdigit/article/category/1264541 有比较全面的学习资源,本文不做过多着墨。另外若有自定义SQL需求,则需要把自定义Xml文件放到另外目录,以免被CodeSmith覆盖。Xml文件结构如下:

  1 <?xml version="1.0" encoding="utf-8" ?>
  2 <EntityMapper  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  3     <TableType>
  4         <TableName>Bas_Bank</TableName>
  5         <TypeFullName>XFramework.Model.Bas_Bank</TypeFullName>
  6     </TableType>
  7     <Properties>
  8         <Property>
  9             <Name>CompanyID</Name>
 10             <DbType>AnsiString</DbType>
 11             <NativeType>varchar</NativeType>
 12             <Precision>0</Precision>
 13             <Scale>0</Scale>
 14             <Size>10</Size>
 15         </Property>
 16         <Property>
 17             <Name>BankID</Name>
 18             <DbType>AnsiString</DbType>
 19             <NativeType>varchar</NativeType>
 20             <Precision>0</Precision>
 21             <Scale>0</Scale>
 22             <Size>20</Size>
 23         </Property>
 24         <Property>
 25             <Name>BankCode</Name>
 26             <DbType>String</DbType>
 27             <NativeType>nvarchar</NativeType>
 28             <Precision>0</Precision>
 29             <Scale>0</Scale>
 30             <Size>20</Size>
 31         </Property>
 32         <Property>
 33             <Name>BankName</Name>
 34             <DbType>String</DbType>
 35             <NativeType>nvarchar</NativeType>
 36             <Precision>0</Precision>
 37             <Scale>0</Scale>
 38             <Size>40</Size>
 39         </Property>
 40         <Property>
 41             <Name>SWIFT</Name>
 42             <DbType>String</DbType>
 43             <NativeType>nvarchar</NativeType>
 44             <Precision>0</Precision>
 45             <Scale>0</Scale>
 46             <Size>20</Size>
 47         </Property>
 48         <Property>
 49             <Name>AreaID</Name>
 50             <DbType>AnsiString</DbType>
 51             <NativeType>varchar</NativeType>
 52             <Precision>0</Precision>
 53             <Scale>0</Scale>
 54             <Size>19</Size>
 55         </Property>
 56         <Property>
 57             <Name>Address</Name>
 58             <DbType>String</DbType>
 59             <NativeType>nvarchar</NativeType>
 60             <Precision>0</Precision>
 61             <Scale>0</Scale>
 62             <Size>100</Size>
 63         </Property>
 64         <Property>
 65             <Name>Phone</Name>
 66             <DbType>AnsiString</DbType>
 67             <NativeType>varchar</NativeType>
 68             <Precision>0</Precision>
 69             <Scale>0</Scale>
 70             <Size>60</Size>
 71         </Property>
 72         <Property>
 73             <Name>ParentID</Name>
 74             <DbType>AnsiString</DbType>
 75             <NativeType>varchar</NativeType>
 76             <Precision>0</Precision>
 77             <Scale>0</Scale>
 78             <Size>20</Size>
 79         </Property>
 80         <Property>
 81             <Name>Level</Name>
 82             <DbType>Int32</DbType>
 83             <NativeType>int</NativeType>
 84             <Precision>10</Precision>
 85             <Scale>0</Scale>
 86             <Size>4</Size>
 87         </Property>
 88         <Property>
 89             <Name>IsDetail</Name>
 90             <DbType>Boolean</DbType>
 91             <NativeType>bit</NativeType>
 92             <Precision>1</Precision>
 93             <Scale>0</Scale>
 94             <Size>1</Size>
 95         </Property>
 96         <Property>
 97             <Name>FullName</Name>
 98             <DbType>String</DbType>
 99             <NativeType>nvarchar</NativeType>
100             <Precision>0</Precision>
101             <Scale>0</Scale>
102             <Size>100</Size>
103         </Property>
104         <Property>
105             <Name>FullParentID</Name>
106             <DbType>String</DbType>
107             <NativeType>nvarchar</NativeType>
108             <Precision>0</Precision>
109             <Scale>0</Scale>
110             <Size>80</Size>
111         </Property>
112         <Property>
113             <Name>ModifyDTM</Name>
114             <DbType>DateTime</DbType>
115             <NativeType>datetime</NativeType>
116             <Precision>23</Precision>
117             <Scale>3</Scale>
118             <Size>8</Size>
119         </Property>
120         <Property>
121             <Name>Remark</Name>
122             <DbType>String</DbType>
123             <NativeType>nvarchar</NativeType>
124             <Precision>0</Precision>
125             <Scale>0</Scale>
126             <Size>200</Size>
127         </Property>
128         <Property>
129             <Name>AllowUsed</Name>
130             <DbType>Boolean</DbType>
131             <NativeType>bit</NativeType>
132             <Precision>1</Precision>
133             <Scale>0</Scale>
134             <Size>1</Size>
135         </Property>
136     </Properties>
137     <Keys>
138         <Property>
139             <Name>CompanyID</Name>
140             <DbType>AnsiString</DbType>
141             <NativeType>varchar</NativeType>
142             <Precision>0</Precision>
143             <Scale>0</Scale>
144             <Size>10</Size>
145         </Property>
146         <Property>
147             <Name>BankID</Name>
148             <DbType>AnsiString</DbType>
149             <NativeType>varchar</NativeType>
150             <Precision>0</Precision>
151             <Scale>0</Scale>
152             <Size>20</Size>
153         </Property>
154     </Keys>
155     <Commands>
156         <Command>
157             <Key>Select</Key>
158             <CommandType>Text</CommandType>
159             <Text>
160              SELECT
161             [CompanyID],
162             [BankID],
163             [BankCode],
164             [BankName],
165             [SWIFT],
166             [AreaID],
167             [Address],
168             [Phone],
169             [ParentID],
170             [Level],
171             [IsDetail],
172             [FullName],
173             [FullParentID],
174             [ModifyDTM],
175             [Remark],
176             [AllowUsed]
177             FROM [Bas_Bank]
178             WHERE 1=1 #WHERE#
179             </Text>
180         </Command>
181         <Command>
182             <Key>SelectByPaging</Key>
183             <CommandType>Text</CommandType>
184             <Text>
185             SELECT
186                 [CompanyID],
187                 [BankID],
188                 [BankCode],
189                 [BankName],
190                 [SWIFT],
191                 [AreaID],
192                 [Address],
193                 [Phone],
194                 [ParentID],
195                 [Level],
196                 [IsDetail],
197                 [FullName],
198                 [FullParentID],
199                 [ModifyDTM],
200                 [Remark],
201                 [AllowUsed],
202                 [XRecordCount],
203                 [XRowNum]
204             FROM(
205                 SELECT
206                     [CompanyID],
207                     [BankID],
208                     [BankCode],
209                     [BankName],
210                     [SWIFT],
211                     [AreaID],
212                     [Address],
213                     [Phone],
214                     [ParentID],
215                     [Level],
216                     [IsDetail],
217                     [FullName],
218                     [FullParentID],
219                     [ModifyDTM],
220                     [Remark],
221                     [AllowUsed],
222                     Count(*) Over() as [XRecordCount],
223                     Row_Number() Over(Order By [CompanyID],[BankID],[BankCode],[BankName],[SWIFT],[AreaID],[Address],[Phone],[ParentID],[Level],[IsDetail],[FullName],[FullParentID],[ModifyDTM],[Remark],[AllowUsed]) as [XRowNum]
224                 FROM [Bas_Bank]
225                 WHERE 1=1 #WHERE#
226             ) a WHERE [XRowNum] BETWEEN #BETWEEN#
227             </Text>
228         </Command>
229         <Command>
230             <Key>SelectByKey</Key>
231             <CommandType>Text</CommandType>
232             <Text>
233              SELECT
234             [CompanyID],
235             [BankID],
236             [BankCode],
237             [BankName],
238             [SWIFT],
239             [AreaID],
240             [Address],
241             [Phone],
242             [ParentID],
243             [Level],
244             [IsDetail],
245             [FullName],
246             [FullParentID],
247             [ModifyDTM],
248             [Remark],
249             [AllowUsed]
250             FROM [Bas_Bank]
251             WHERE 1=1
252             And [CompanyID]=@CompanyID
253             And [BankID]=@BankID
254             </Text>
255             <Parameters>
256                 <Parameter>
257                     <Name>CompanyID</Name>
258                     <DbType>AnsiString</DbType>
259                     <NativeType>varchar</NativeType>
260                     <Precision>0</Precision>
261                     <Scale>0</Scale>
262                     <Size>10</Size>
263                 </Parameter>
264                 <Parameter>
265                     <Name>BankID</Name>
266                     <DbType>AnsiString</DbType>
267                     <NativeType>varchar</NativeType>
268                     <Precision>0</Precision>
269                     <Scale>0</Scale>
270                     <Size>20</Size>
271                 </Parameter>
272             </Parameters>
273         </Command>
274         <Command>
275             <Key>Update</Key>
276             <CommandType>Text</CommandType>
277             <Text>
278             UPDATE [Bas_Bank] SET
279                     [BankCode] = @BankCode,
280                     [BankName] = @BankName,
281                     [SWIFT] = @SWIFT,
282                     [AreaID] = @AreaID,
283                     [Address] = @Address,
284                     [Phone] = @Phone,
285                     [ParentID] = @ParentID,
286                     [Level] = @Level,
287                     [IsDetail] = @IsDetail,
288                     [FullName] = @FullName,
289                     [FullParentID] = @FullParentID,
290                     [ModifyDTM] = @ModifyDTM,
291                     [Remark] = @Remark,
292                     [AllowUsed] = @AllowUsed
293             WHERE 1=1  #WHERE#
294             </Text>
295             <Parameters>
296                 <Parameter>
297                     <Name>BankCode</Name>
298                     <DbType>String</DbType>
299                     <NativeType>nvarchar</NativeType>
300                     <Precision>0</Precision>
301                     <Scale>0</Scale>
302                     <Size>20</Size>
303                 </Parameter>
304                 <Parameter>
305                     <Name>BankName</Name>
306                     <DbType>String</DbType>
307                     <NativeType>nvarchar</NativeType>
308                     <Precision>0</Precision>
309                     <Scale>0</Scale>
310                     <Size>40</Size>
311                 </Parameter>
312                 <Parameter>
313                     <Name>SWIFT</Name>
314                     <DbType>String</DbType>
315                     <NativeType>nvarchar</NativeType>
316                     <Precision>0</Precision>
317                     <Scale>0</Scale>
318                     <Size>20</Size>
319                 </Parameter>
320                 <Parameter>
321                     <Name>AreaID</Name>
322                     <DbType>AnsiString</DbType>
323                     <NativeType>varchar</NativeType>
324                     <Precision>0</Precision>
325                     <Scale>0</Scale>
326                     <Size>19</Size>
327                 </Parameter>
328                 <Parameter>
329                     <Name>Address</Name>
330                     <DbType>String</DbType>
331                     <NativeType>nvarchar</NativeType>
332                     <Precision>0</Precision>
333                     <Scale>0</Scale>
334                     <Size>100</Size>
335                 </Parameter>
336                 <Parameter>
337                     <Name>Phone</Name>
338                     <DbType>AnsiString</DbType>
339                     <NativeType>varchar</NativeType>
340                     <Precision>0</Precision>
341                     <Scale>0</Scale>
342                     <Size>60</Size>
343                 </Parameter>
344                 <Parameter>
345                     <Name>ParentID</Name>
346                     <DbType>AnsiString</DbType>
347                     <NativeType>varchar</NativeType>
348                     <Precision>0</Precision>
349                     <Scale>0</Scale>
350                     <Size>20</Size>
351                 </Parameter>
352                 <Parameter>
353                     <Name>Level</Name>
354                     <DbType>Int32</DbType>
355                     <NativeType>int</NativeType>
356                     <Precision>10</Precision>
357                     <Scale>0</Scale>
358                     <Size>4</Size>
359                 </Parameter>
360                 <Parameter>
361                     <Name>IsDetail</Name>
362                     <DbType>Boolean</DbType>
363                     <NativeType>bit</NativeType>
364                     <Precision>1</Precision>
365                     <Scale>0</Scale>
366                     <Size>1</Size>
367                 </Parameter>
368                 <Parameter>
369                     <Name>FullName</Name>
370                     <DbType>String</DbType>
371                     <NativeType>nvarchar</NativeType>
372                     <Precision>0</Precision>
373                     <Scale>0</Scale>
374                     <Size>100</Size>
375                 </Parameter>
376                 <Parameter>
377                     <Name>FullParentID</Name>
378                     <DbType>String</DbType>
379                     <NativeType>nvarchar</NativeType>
380                     <Precision>0</Precision>
381                     <Scale>0</Scale>
382                     <Size>80</Size>
383                 </Parameter>
384                 <Parameter>
385                     <Name>ModifyDTM</Name>
386                     <DbType>DateTime</DbType>
387                     <NativeType>datetime</NativeType>
388                     <Precision>23</Precision>
389                     <Scale>3</Scale>
390                     <Size>8</Size>
391                 </Parameter>
392                 <Parameter>
393                     <Name>Remark</Name>
394                     <DbType>String</DbType>
395                     <NativeType>nvarchar</NativeType>
396                     <Precision>0</Precision>
397                     <Scale>0</Scale>
398                     <Size>200</Size>
399                 </Parameter>
400                 <Parameter>
401                     <Name>AllowUsed</Name>
402                     <DbType>Boolean</DbType>
403                     <NativeType>bit</NativeType>
404                     <Precision>1</Precision>
405                     <Scale>0</Scale>
406                     <Size>1</Size>
407                 </Parameter>
408             </Parameters>
409         </Command>
410         <Command>
411             <Key>UpdateByKey</Key>
412             <CommandType>Text</CommandType>
413             <Text>
414             UPDATE [Bas_Bank] SET
415                     [BankCode] = @BankCode,
416                     [BankName] = @BankName,
417                     [SWIFT] = @SWIFT,
418                     [AreaID] = @AreaID,
419                     [Address] = @Address,
420                     [Phone] = @Phone,
421                     [ParentID] = @ParentID,
422                     [Level] = @Level,
423                     [IsDetail] = @IsDetail,
424                     [FullName] = @FullName,
425                     [FullParentID] = @FullParentID,
426                     [ModifyDTM] = @ModifyDTM,
427                     [Remark] = @Remark,
428                     [AllowUsed] = @AllowUsed
429             WHERE 1=1
430             And [CompanyID]=@CompanyID
431             And [BankID]=@BankID
432             </Text>
433             <Parameters>
434                 <Parameter>
435                     <Name>BankCode</Name>
436                     <DbType>String</DbType>
437                     <NativeType>nvarchar</NativeType>
438                     <Precision>0</Precision>
439                     <Scale>0</Scale>
440                     <Size>20</Size>
441                 </Parameter>
442                 <Parameter>
443                     <Name>BankName</Name>
444                     <DbType>String</DbType>
445                     <NativeType>nvarchar</NativeType>
446                     <Precision>0</Precision>
447                     <Scale>0</Scale>
448                     <Size>40</Size>
449                 </Parameter>
450                 <Parameter>
451                     <Name>SWIFT</Name>
452                     <DbType>String</DbType>
453                     <NativeType>nvarchar</NativeType>
454                     <Precision>0</Precision>
455                     <Scale>0</Scale>
456                     <Size>20</Size>
457                 </Parameter>
458                 <Parameter>
459                     <Name>AreaID</Name>
460                     <DbType>AnsiString</DbType>
461                     <NativeType>varchar</NativeType>
462                     <Precision>0</Precision>
463                     <Scale>0</Scale>
464                     <Size>19</Size>
465                 </Parameter>
466                 <Parameter>
467                     <Name>Address</Name>
468                     <DbType>String</DbType>
469                     <NativeType>nvarchar</NativeType>
470                     <Precision>0</Precision>
471                     <Scale>0</Scale>
472                     <Size>100</Size>
473                 </Parameter>
474                 <Parameter>
475                     <Name>Phone</Name>
476                     <DbType>AnsiString</DbType>
477                     <NativeType>varchar</NativeType>
478                     <Precision>0</Precision>
479                     <Scale>0</Scale>
480                     <Size>60</Size>
481                 </Parameter>
482                 <Parameter>
483                     <Name>ParentID</Name>
484                     <DbType>AnsiString</DbType>
485                     <NativeType>varchar</NativeType>
486                     <Precision>0</Precision>
487                     <Scale>0</Scale>
488                     <Size>20</Size>
489                 </Parameter>
490                 <Parameter>
491                     <Name>Level</Name>
492                     <DbType>Int32</DbType>
493                     <NativeType>int</NativeType>
494                     <Precision>10</Precision>
495                     <Scale>0</Scale>
496                     <Size>4</Size>
497                 </Parameter>
498                 <Parameter>
499                     <Name>IsDetail</Name>
500                     <DbType>Boolean</DbType>
501                     <NativeType>bit</NativeType>
502                     <Precision>1</Precision>
503                     <Scale>0</Scale>
504                     <Size>1</Size>
505                 </Parameter>
506                 <Parameter>
507                     <Name>FullName</Name>
508                     <DbType>String</DbType>
509                     <NativeType>nvarchar</NativeType>
510                     <Precision>0</Precision>
511                     <Scale>0</Scale>
512                     <Size>100</Size>
513                 </Parameter>
514                 <Parameter>
515                     <Name>FullParentID</Name>
516                     <DbType>String</DbType>
517                     <NativeType>nvarchar</NativeType>
518                     <Precision>0</Precision>
519                     <Scale>0</Scale>
520                     <Size>80</Size>
521                 </Parameter>
522                 <Parameter>
523                     <Name>ModifyDTM</Name>
524                     <DbType>DateTime</DbType>
525                     <NativeType>datetime</NativeType>
526                     <Precision>23</Precision>
527                     <Scale>3</Scale>
528                     <Size>8</Size>
529                 </Parameter>
530                 <Parameter>
531                     <Name>Remark</Name>
532                     <DbType>String</DbType>
533                     <NativeType>nvarchar</NativeType>
534                     <Precision>0</Precision>
535                     <Scale>0</Scale>
536                     <Size>200</Size>
537                 </Parameter>
538                 <Parameter>
539                     <Name>AllowUsed</Name>
540                     <DbType>Boolean</DbType>
541                     <NativeType>bit</NativeType>
542                     <Precision>1</Precision>
543                     <Scale>0</Scale>
544                     <Size>1</Size>
545                 </Parameter>
546                 <Parameter>
547                     <Name>CompanyID</Name>
548                     <DbType>AnsiString</DbType>
549                     <NativeType>varchar</NativeType>
550                     <Precision>0</Precision>
551                     <Scale>0</Scale>
552                     <Size>10</Size>
553                 </Parameter>
554                 <Parameter>
555                     <Name>BankID</Name>
556                     <DbType>AnsiString</DbType>
557                     <NativeType>varchar</NativeType>
558                     <Precision>0</Precision>
559                     <Scale>0</Scale>
560                     <Size>20</Size>
561                 </Parameter>
562             </Parameters>
563         </Command>
564         <Command>
565             <Key>UpdateByExpr</Key>
566             <CommandType>Text</CommandType>
567             <Text>
568             UPDATE [Bas_Bank] SET
569             #SET#
570             WHERE 1=1  #WHERE#
571             </Text>
572         </Command>
573         <Command>
574             <Key>Insert</Key>
575             <CommandType>Text</CommandType>
576             <Text>
577             INSERT INTO [Bas_Bank](
578                     [CompanyID],
579                     [BankID],
580                     [BankCode],
581                     [BankName],
582                     [SWIFT],
583                     [AreaID],
584                     [Address],
585                     [Phone],
586                     [ParentID],
587                     [Level],
588                     [IsDetail],
589                     [FullName],
590                     [FullParentID],
591                     [ModifyDTM],
592                     [Remark],
593                     [AllowUsed]
594             ) VALUES(
595                     @CompanyID,
596                     @BankID,
597                     @BankCode,
598                     @BankName,
599                     @SWIFT,
600                     @AreaID,
601                     @Address,
602                     @Phone,
603                     @ParentID,
604                     @Level,
605                     @IsDetail,
606                     @FullName,
607                     @FullParentID,
608                     @ModifyDTM,
609                     @Remark,
610                     @AllowUsed
611             )
612
613             </Text>
614             <Parameters>
615                 <Parameter>
616                     <Name>CompanyID</Name>
617                     <DbType>AnsiString</DbType>
618                     <NativeType>varchar</NativeType>
619                     <Precision>0</Precision>
620                     <Scale>0</Scale>
621                     <Size>10</Size>
622                 </Parameter>
623                 <Parameter>
624                     <Name>BankID</Name>
625                     <DbType>AnsiString</DbType>
626                     <NativeType>varchar</NativeType>
627                     <Precision>0</Precision>
628                     <Scale>0</Scale>
629                     <Size>20</Size>
630                 </Parameter>
631                 <Parameter>
632                     <Name>BankCode</Name>
633                     <DbType>String</DbType>
634                     <NativeType>nvarchar</NativeType>
635                     <Precision>0</Precision>
636                     <Scale>0</Scale>
637                     <Size>20</Size>
638                 </Parameter>
639                 <Parameter>
640                     <Name>BankName</Name>
641                     <DbType>String</DbType>
642                     <NativeType>nvarchar</NativeType>
643                     <Precision>0</Precision>
644                     <Scale>0</Scale>
645                     <Size>40</Size>
646                 </Parameter>
647                 <Parameter>
648                     <Name>SWIFT</Name>
649                     <DbType>String</DbType>
650                     <NativeType>nvarchar</NativeType>
651                     <Precision>0</Precision>
652                     <Scale>0</Scale>
653                     <Size>20</Size>
654                 </Parameter>
655                 <Parameter>
656                     <Name>AreaID</Name>
657                     <DbType>AnsiString</DbType>
658                     <NativeType>varchar</NativeType>
659                     <Precision>0</Precision>
660                     <Scale>0</Scale>
661                     <Size>19</Size>
662                 </Parameter>
663                 <Parameter>
664                     <Name>Address</Name>
665                     <DbType>String</DbType>
666                     <NativeType>nvarchar</NativeType>
667                     <Precision>0</Precision>
668                     <Scale>0</Scale>
669                     <Size>100</Size>
670                 </Parameter>
671                 <Parameter>
672                     <Name>Phone</Name>
673                     <DbType>AnsiString</DbType>
674                     <NativeType>varchar</NativeType>
675                     <Precision>0</Precision>
676                     <Scale>0</Scale>
677                     <Size>60</Size>
678                 </Parameter>
679                 <Parameter>
680                     <Name>ParentID</Name>
681                     <DbType>AnsiString</DbType>
682                     <NativeType>varchar</NativeType>
683                     <Precision>0</Precision>
684                     <Scale>0</Scale>
685                     <Size>20</Size>
686                 </Parameter>
687                 <Parameter>
688                     <Name>Level</Name>
689                     <DbType>Int32</DbType>
690                     <NativeType>int</NativeType>
691                     <Precision>10</Precision>
692                     <Scale>0</Scale>
693                     <Size>4</Size>
694                 </Parameter>
695                 <Parameter>
696                     <Name>IsDetail</Name>
697                     <DbType>Boolean</DbType>
698                     <NativeType>bit</NativeType>
699                     <Precision>1</Precision>
700                     <Scale>0</Scale>
701                     <Size>1</Size>
702                 </Parameter>
703                 <Parameter>
704                     <Name>FullName</Name>
705                     <DbType>String</DbType>
706                     <NativeType>nvarchar</NativeType>
707                     <Precision>0</Precision>
708                     <Scale>0</Scale>
709                     <Size>100</Size>
710                 </Parameter>
711                 <Parameter>
712                     <Name>FullParentID</Name>
713                     <DbType>String</DbType>
714                     <NativeType>nvarchar</NativeType>
715                     <Precision>0</Precision>
716                     <Scale>0</Scale>
717                     <Size>80</Size>
718                 </Parameter>
719                 <Parameter>
720                     <Name>ModifyDTM</Name>
721                     <DbType>DateTime</DbType>
722                     <NativeType>datetime</NativeType>
723                     <Precision>23</Precision>
724                     <Scale>3</Scale>
725                     <Size>8</Size>
726                 </Parameter>
727                 <Parameter>
728                     <Name>Remark</Name>
729                     <DbType>String</DbType>
730                     <NativeType>nvarchar</NativeType>
731                     <Precision>0</Precision>
732                     <Scale>0</Scale>
733                     <Size>200</Size>
734                 </Parameter>
735                 <Parameter>
736                     <Name>AllowUsed</Name>
737                     <DbType>Boolean</DbType>
738                     <NativeType>bit</NativeType>
739                     <Precision>1</Precision>
740                     <Scale>0</Scale>
741                     <Size>1</Size>
742                 </Parameter>
743             </Parameters>
744         </Command>
745         <Command>
746             <Key>Delete</Key>
747             <CommandType>Text</CommandType>
748             <Text>
749             DELETE FROM [Bas_Bank]
750             WHERE 1=1  #WHERE#
751             </Text>
752         </Command>
753         <Command>
754             <Key>DeleteByKey</Key>
755             <CommandType>Text</CommandType>
756             <Text>
757             DELETE FROM [Bas_Bank]
758             WHERE 1=1
759             And [CompanyID]=@CompanyID
760             And [BankID]=@BankID
761             </Text>
762             <Parameters>
763                 <Parameter>
764                     <Name>CompanyID</Name>
765                     <DbType>AnsiString</DbType>
766                     <NativeType>varchar</NativeType>
767                     <Precision>0</Precision>
768                     <Scale>0</Scale>
769                     <Size>10</Size>
770                 </Parameter>
771                 <Parameter>
772                     <Name>BankID</Name>
773                     <DbType>AnsiString</DbType>
774                     <NativeType>varchar</NativeType>
775                     <Precision>0</Precision>
776                     <Scale>0</Scale>
777                     <Size>20</Size>
778                 </Parameter>
779             </Parameters>
780         </Command>
781     </Commands>
782 </EntityMapper>

  注意看Command节点,可以简单理解为数据库命令(下称命令),比较关键的是Text和Parameters子节点。这些命令有的带有参数有的则没有,没带参数的会有一个 ## 占位符。没带参数的命0000000令,其参数可能通过硬编码生成也有可能通过解析Lambda表达式生成,如何解析Lambda表达式会在接下来的第二点介绍。带有参数的命令,其参数名跟字段名一致,根据实体实例与字段名称就可以确定参数的值。

 1     public Command Build<T>(string cmdName, T TEntity)
 2         where T : class
 3     {
 4         Command cmd = this.GetCommand(typeof(T), cmdName);
 5         foreach (Parameter parameter in cmd.Parameters)
 6         {
 7             //赋参数值
 8             object value = AccFacHelper.Get(TEntity, parameter.Name);
 9             parameter.Value = value;
10         }
11
12         return cmd;
13     }

  2. 如何将Lambda表达式解析成查询条件

  很早之前大牛老赵就写过一篇博文 [扩展LINQ to SQL:使用Lambda Expression批量删除数据],基本思路是实现一个Expression<Func<T,bool>>解析器并将Lambda解析为最终需要执行的TSQL。但是老赵的实现并不完整,不能解析像 f=>true f=>!f.FieldName f=>string.Length f=>string[].Contains(s) 等表达式。我在他的基础上再增加了处理,并且把条件和参数分开来以适应Dapper的参数要求,看代码片段:

 1   case ExpressionType.Constant:
 2         //True常量解析成1==1 Flase常量解析成1==2
 3         bool value = Convert.ToBoolean(((ConstantExpression)expr).Value);
 4         leftExpr = Expression.Constant(1);
 5         rightExpr = Expression.Constant(value ? 1 : 2);
 6
 7         break;
 8
 9   ... ...
10
11   string condition = b.NodeType == ExpressionType.Coalesce ?
12         string.Format("({0}({1},{2}))", opr, left, right) :
13         string.Format("({0} {1} {2})", left, opr, right);
14
15   ......
16
17   condition = string.Format(" AND {0}", _stcConditions.Pop());
18     MatchCollection matches = Regex.Matches(condition, string.Format(@"{0}(?<Name>p(?<Index>[0-9]+))", _parameterPrefix));
19     foreach (Match match in matches)
20     {
21         if (!match.Success) continue;
22
23         string index = match.Groups["Index"].Value;
24         string parameterName = match.Groups["Name"].Value;
25         if (_parameters[parameterName] == null) _parameters.Add(parameterName, _lstArguments[Convert.ToInt32(index)]);
26     }

  3. 如何将Dapper返回的IDataReader转化成DataTable和DataSet

  IDataReader转化成DataTable相对容易,直接调用DataTable.Load(IDataReader)重载就可以,比较麻烦的是转成DataSet。DataSet.Load方法的三个重载都要传递DataTable[]形参,但在IDataReader填充DataSet之前我们是无法知道它包含有多少个数据集,也就无法确定如何给DataSet.Load传参,这似乎真的是个互相矛盾的命题。先别着急,想想之前经常用的SqlDataAdapter,它就有SqlDataAdapter.Fill(DataSet)重载。它能直接填充DataSet而不用传递DataTable[]形参,那么理论上来说DataSet.Load方法也不需要传递才对,因为实际上无论是DataSet.Load还是SqlDataAdapter.Fill,它们里面无非都是对IDataReader的层层封装而已。如此看来,只要弄清楚SqlDataAdapter.Fill(DataSet)重载,我们的问题便会迎刃而解了。

  祭出反编译利器.NET Reflector,先来看看SqlDataAdapter.Fill(DataSet)到底都干了些什么:  

 1 public abstract class DbDataAdapter : DataAdapter, IDbDataAdapter, IDataAdapter, ICloneable
 2 {
 3     public override int Fill(DataSet dataSet)
 4     {
 5         try
 6         {
 7             IDbCommand selectCommand = this._IDbDataAdapter.SelectCommand;
 8             CommandBehavior fillCommandBehavior = this.FillCommandBehavior;
 9             num = this.Fill(dataSet, 0, 0, "Table", selectCommand, fillCommandBehavior);
10         }
11         finally
12         {
13             Bid.ScopeLeave(ref ptr);
14         }
15         return num;
16     }
17 }
18
19 public abstract class DbDataAdapter : DataAdapter, IDbDataAdapter, IDataAdapter, ICloneable
20 {
21     protected virtual int Fill(DataSet dataSet, int startRecord, int maxRecords, string srcTable, IDbCommand command, CommandBehavior behavior)
22     {
23         try
24         {
25             //srcTable="Table",注意跟踪形参
26             num = this.FillInternal(dataSet, null, startRecord, maxRecords, srcTable, command, behavior);
27         }
28         finally
29         {
30             Bid.ScopeLeave(ref ptr);
31         }
32         return num;
33     }
34 }
35
36 public abstract class DbDataAdapter : DataAdapter, IDbDataAdapter, IDataAdapter, ICloneable
37 {
38     private int FillInternal(DataSet dataset, DataTable[] datatables, int startRecord, int maxRecords, string srcTable, IDbCommand command, CommandBehavior behavior)
39     {
40         bool flag = null == command.Connection;
41         try
42         {
43             try
44             {
45                 using (IDataReader reader = null)
46                 {
47                     reader = command.ExecuteReader(behavior);
48                     ... ...
49                     return this.Fill(dataset, srcTable, reader, startRecord, maxRecords);
50                 }
51             }
52             finally
53             {
54                 QuietClose(connection, open);
55             }
56         }
57         finally
58         {
59             if (flag)
60             {
61                 command.Transaction = null;
62                 command.Connection = null;
63             }
64         }
65         return 0;
66     }
67 }
68
69 public class DataAdapter : Component, IDataAdapter
70 {
71     protected virtual int Fill(DataSet dataSet, string srcTable, IDataReader dataReader, int startRecord, int maxRecords)
72     {
73         try
74         {
75             DataReaderContainer container = DataReaderContainer.Create(dataReader, this.ReturnProviderSpecificTypes);
76             num = this.FillFromReader(dataSet, null, srcTable, container, startRecord, maxRecords, null, null);
77         }
78         finally
79         {
80             Bid.ScopeLeave(ref ptr);
81         }
82         return num;
83     }
84 }

  看到了没,SqlDataAdapter.Fill(DataSet)方法内部是调用了另外一个重载,形参srcTable就是一个硬编码的"Table"。

  再来看看DataSet.Load的内部处理:

 1 public class DataSet : MarshalByValueComponent, IListSource, IXmlSerializable, ISupportInitializeNotification, ISupportInitialize, ISerializable
 2 {
 3     public virtual void Load(IDataReader reader, LoadOption loadOption, FillErrorEventHandler errorHandler, params DataTable[] tables)
 4     {
 5         try
 6         {
 7             LoadAdapter adapter = new LoadAdapter {
 8                 FillLoadOption = loadOption,
 9                 MissingSchemaAction = MissingSchemaAction.AddWithKey
10             };
11             if (errorHandler != null)
12             {
13                 adapter.FillError += errorHandler;
14             }
15             adapter.FillFromReader(tables, reader, 0, 0);
16             ... ...
17         }
18         finally
19         {
20             ... ...
21         }
22     }
23 }
24
25 internal sealed class LoadAdapter : DataAdapter
26 {
27     internal int FillFromReader(DataTable[] dataTables, IDataReader dataReader, int startRecord, int maxRecords)
28     {
29         return this.Fill(dataTables, dataReader, startRecord, maxRecords);
30     }
31 }
32
33  

  假如我们把LoadAdapter.FillFromReader方法修改一个,调用LoadAdapter.Fill的另外一个重载LoadAdapter.Fill(DataSet,string,IDataReader,int,int),而第二个形参只需要传"Table"而已。最终完成代码:

 1 /// <summary>
 2 /// 数据适配器,扩展Fill方法
 3 /// .NET的DataSet.Load方法,底层调用DataAdapter.Fill(DataTable[], IDataReader, int, int)
 4 /// Dapper想要返回DataSet,需要重写Load方法,不必传入DataTable[],因为数组长度不确定
 5 /// </summary>
 6 public class XLoadAdapter : DataAdapter
 7 {
 8     public XLoadAdapter()
 9     {
10     }
11
12     public int FillFromReader(DataSet ds, IDataReader dataReader, int startRecord, int maxRecords)
13     {
14         return this.Fill(ds, "Table", dataReader, startRecord, maxRecords);
15     }
16 }
17
18 /// <summary>
19 /// 扩展Load方法
20 /// </summary>
21 public class XDataSet : DataSet
22 {
23     public override void Load(IDataReader reader, LoadOption loadOption, FillErrorEventHandler handler, params DataTable[] tables)
24     {
25         XLoadAdapter adapter = new XLoadAdapter
26         {
27             FillLoadOption = loadOption,
28             MissingSchemaAction = MissingSchemaAction.AddWithKey
29         };
30         if (handler != null)
31         {
32             adapter.FillError += handler;
33         }
34         adapter.FillFromReader(this, reader, 0, 0);
35         if (!reader.IsClosed && !reader.NextResult())
36         {
37             reader.Close();
38         }
39     }
40 }
41
42 //调用
43 IDataReader reader = _session.Connection.ExecuteReader(command, dynParameters,
44     _session.Transaction, _session.DataSource.CommandTimeout, commandType);
45 DataSet ds = new XDataSet();
46 ds.Load(reader, LoadOption.OverwriteChanges, null, new DataTable[] { });

  4. 总结

  本框架在Dapper的基础上再做封装,支持Lambda表达式树查询也支持纯Sql查询,相对来说比较灵活。但限于个人水平,没有把EmitMapper完美整合进来,只是简单的进行了引用,如果朋友们有好的建议,在下诚心请教。需要源码的朋友留个QQ邮箱我单独发吧,园子的附件最大10M导致源码上传不了。(已上传至百度云盘 http://pan.baidu.com/s/1mihKTZU)

 
分类: 数据访问
标签: Dapper数据访问
 
 
 
 

【原创】重复造轮子之高仿EntityFramework

 
  • 前言

在上一篇《【原创】打造基于Dapper的数据访问层》中,Dapper在应付多表自由关联、分组查询、匿名查询等应用场景时经常要手动写SQL语句。看着代码里满屏的红色SQL字符串,简直头大,于是便萌生重复造ORM这个轮子的念头。本ORM在API设计上最大程度地借鉴 EF 的写法,支持链式查询(点标记)、查询表达式、聚合查询、分组排序、批量插入、批量更新、批量删除、1:1关系外键等。在实体绑定层面,使用 Emit 来动态构建绑定指令,性能最大限度地接近原生水平。

  • 性能

7000笔记录循环读1000次,同时加载1:1关系的外键,速度比 EF 稍快。

  • 语法

1. 单表查询

// 查询表达式
var query = from a in context.GetTable<Inte_CRM.Demo>()
            select a;
var r1 = query.ToList();
// 点标记
query = context.GetTable<Inte_CRM.Demo>();
r1 = query.ToList();
//SQL=>
//SELECT
//t0.[DemoId] AS [DemoId],
//t0.[DemoCode] AS [DemoCode],
//t0.[DemoName] AS [DemoName],
//...
//t0.[DemoLong] AS [DemoLong],
//t0.[DemoLong_Nullable] AS [DemoLong_Nullable]
//FROM [Sys_Demo] t0

2. 关联查询

// INNER JOIN
var query =
    from a in context.GetTable<Inte_CRM.CRM_SaleOrder>()
    join b in context.GetTable<Inte_CRM.Client>() on a.ClientId equals b.ClientId
    join c in context.GetTable<Inte_CRM.CloudServer>() on b.CloudServerId equals c.CloudServerId
    where a.ClientId > 0
    select a;
var r1 = query.ToList();
// 点标记
query = context
    .GetTable<Inte_CRM.CRM_SaleOrder>()
    .Join(context.GetTable<Inte_CRM.Client>(), a => a.ClientId, b => b.ClientId, (a, b) => new { Sale = a, Buyer = b })
    .Join(context.GetTable<Inte_CRM.CloudServer>(), b => b.Buyer.CloudServerId, c => c.CloudServerId, (a, c) => new Inte_CRM.CRM_SaleOrder { })
    .Where(a => a.ClientId > 0);
//r1 = query.ToList();
//SQL=>
//SELECT
//t0.[OrderId] AS [OrderId],
//t0.[OrderNo] AS [OrderNo],
//t0.[Remark] AS [Remark],
//t0.[ClientId] AS [ClientId]
//FROM [CRM_SaleOrder] t0
//INNER JOIN [Bas_Client] t1 ON t0.[ClientId] = t1.[ClientId]
//INNER JOIN [Sys_CloudServer] t2 ON t1.[CloudServerId] = t2.[CloudServerId]
//WHERE t0.[ClientId] > 0

3. 分组分页

// 分组后再分页
query =
    from a in context.GetTable<Inte_CRM.Client>()
    where a.ClientName == "TAN"
    group a by new { a.ClientId, a.ClientName } into g
    where g.Key.ClientId > 0
    orderby new { g.Key.ClientName, g.Key.ClientId }
    select new
    {
        Id = g.Key.ClientId,
        Name = g.Min(a => a.ClientId)
    };
query = query.Skip(2).Take(3);
r1 = query.ToList();
//SQL=>
//SELECT
//t0.[Id],
//t0.[Name]
//FROM (
//    SELECT
//    t0.[ClientId] AS [Id],
//    MIN(t0.[ClientId]) AS [Name],
//    t0.[ClientName] AS [ClientName]
//    FROM [Bas_Client] t0
//    WHERE t0.[ClientName] = N'TAN'
//    GROUP BY t0.[ClientId],t0.[ClientName]
//    Having t0.[ClientId] > 0
// ) t0
//ORDER BY t0.[ClientName]
//OFFSET 2 ROWS FETCH NEXT 3 ROWS ONLY 

4. 批量插入

context.Insert<Inte_CRM.Thin>(collection);
context.SubmitChanges();
//SQL=>
//INSERT INTO[Sys_Thin]
//([ThinId],[ThinName])
//VALUES
//(2, N'002'),(3,N'003')

5. 导航属性

// 更简单的赋值方式
// 适用场景:在显示列表时只想显示外键表的一两个字段
query =
    from a in context.GetTable<Inte_CRM.CRM_SaleOrder>()
    select new Inte_CRM.CRM_SaleOrder(a)
    {
        Client = new Inte_CRM.Client(a.Client)
        {
            CloudServer = new Inte_CRM.CloudServer
            {
                CloudServerId = a.Client.CloudServer.CloudServerId,
                CloudServerName = a.Client.CloudServer.CloudServerName
            }
        },
        HeavyBuyer = new Inte_CRM.Client
        {
            ClientId = a.Client.ClientId + 10,
            ClientName = a.Client.ClientName + "_heavy",
            CloudServer = new Inte_CRM.CloudServer
            {
                CloudServerId = a.Client.CloudServer.CloudServerId + 10,
                CloudServerName = a.Client.CloudServer.CloudServerName + "_heavy",
            }
        }
    };
r1 = query.ToList();
//SQL=>
//SELECT
//t0.[OrderId] AS [OrderId],
//t0.[OrderNo] AS [OrderNo],
//t0.[Remark] AS [Remark],
//t0.[ClientId] AS [ClientId],
//t1.[ClientId] AS [ClientId1],
//t1.[ClientCode] AS [ClientCode],
//t1.[ClientName] AS [ClientName],
//t1.[State] AS [State],
//t1.[ActiveDate] AS [ActiveDate],
//t1.[CloudServerId] AS [CloudServerId],
//t2.[CloudServerId] AS [CloudServerId1],
//t2.[CloudServerName] AS [CloudServerName],
//t1.[ClientId] + 10 AS [ClientId2],
//t1.[ClientName] + N'_heavy' AS [ClientName1],
//t2.[CloudServerId] + 10 AS [CloudServerId2],
//t2.[CloudServerName] + N'_heavy' AS [CloudServerName1]
//FROM [CRM_SaleOrder] t0
//LEFT JOIN [Bas_Client] t1 ON t0.[ClientId] = t1.[ClientId]
//LEFT JOIN [Sys_CloudServer] t2 ON t1.[CloudServerId] = t2.[CloudServerId]

其它更多示例在源码的 demo 中有详细说明,源码地址:https://github.com/TANZAME/Inte.XFramework

 
 
 

【原创】重复造轮子之高仿EntityFramework

 
  • 前言

在上一篇《【原创】打造基于Dapper的数据访问层》中,Dapper在应付多表自由关联、分组查询、匿名查询等应用场景时经常要手动写SQL语句。看着代码里满屏的红色SQL字符串,简直头大,于是便萌生重复造ORM这个轮子的念头。本ORM在API设计上最大程度地借鉴 EF 的写法,支持链式查询(点标记)、查询表达式、聚合查询、分组排序、批量插入、批量更新、批量删除、1:1关系外键等。在实体绑定层面,使用 Emit 来动态构建绑定指令,性能最大限度地接近原生水平。

  • 性能

7000笔记录循环读1000次,同时加载1:1关系的外键,速度比 EF 稍快。

  • 语法

1. 单表查询

// 查询表达式
var query = from a in context.GetTable<Inte_CRM.Demo>()
            select a;
var r1 = query.ToList();
// 点标记
query = context.GetTable<Inte_CRM.Demo>();
r1 = query.ToList();
//SQL=>
//SELECT
//t0.[DemoId] AS [DemoId],
//t0.[DemoCode] AS [DemoCode],
//t0.[DemoName] AS [DemoName],
//...
//t0.[DemoLong] AS [DemoLong],
//t0.[DemoLong_Nullable] AS [DemoLong_Nullable]
//FROM [Sys_Demo] t0

2. 关联查询

// INNER JOIN
var query =
    from a in context.GetTable<Inte_CRM.CRM_SaleOrder>()
    join b in context.GetTable<Inte_CRM.Client>() on a.ClientId equals b.ClientId
    join c in context.GetTable<Inte_CRM.CloudServer>() on b.CloudServerId equals c.CloudServerId
    where a.ClientId > 0
    select a;
var r1 = query.ToList();
// 点标记
query = context
    .GetTable<Inte_CRM.CRM_SaleOrder>()
    .Join(context.GetTable<Inte_CRM.Client>(), a => a.ClientId, b => b.ClientId, (a, b) => new { Sale = a, Buyer = b })
    .Join(context.GetTable<Inte_CRM.CloudServer>(), b => b.Buyer.CloudServerId, c => c.CloudServerId, (a, c) => new Inte_CRM.CRM_SaleOrder { })
    .Where(a => a.ClientId > 0);
//r1 = query.ToList();
//SQL=>
//SELECT
//t0.[OrderId] AS [OrderId],
//t0.[OrderNo] AS [OrderNo],
//t0.[Remark] AS [Remark],
//t0.[ClientId] AS [ClientId]
//FROM [CRM_SaleOrder] t0
//INNER JOIN [Bas_Client] t1 ON t0.[ClientId] = t1.[ClientId]
//INNER JOIN [Sys_CloudServer] t2 ON t1.[CloudServerId] = t2.[CloudServerId]
//WHERE t0.[ClientId] > 0

3. 分组分页

// 分组后再分页
query =
    from a in context.GetTable<Inte_CRM.Client>()
    where a.ClientName == "TAN"
    group a by new { a.ClientId, a.ClientName } into g
    where g.Key.ClientId > 0
    orderby new { g.Key.ClientName, g.Key.ClientId }
    select new
    {
        Id = g.Key.ClientId,
        Name = g.Min(a => a.ClientId)
    };
query = query.Skip(2).Take(3);
r1 = query.ToList();
//SQL=>
//SELECT
//t0.[Id],
//t0.[Name]
//FROM (
//    SELECT
//    t0.[ClientId] AS [Id],
//    MIN(t0.[ClientId]) AS [Name],
//    t0.[ClientName] AS [ClientName]
//    FROM [Bas_Client] t0
//    WHERE t0.[ClientName] = N'TAN'
//    GROUP BY t0.[ClientId],t0.[ClientName]
//    Having t0.[ClientId] > 0
// ) t0
//ORDER BY t0.[ClientName]
//OFFSET 2 ROWS FETCH NEXT 3 ROWS ONLY 

4. 批量插入

context.Insert<Inte_CRM.Thin>(collection);
context.SubmitChanges();
//SQL=>
//INSERT INTO[Sys_Thin]
//([ThinId],[ThinName])
//VALUES
//(2, N'002'),(3,N'003')

5. 导航属性

// 更简单的赋值方式
// 适用场景:在显示列表时只想显示外键表的一两个字段
query =
    from a in context.GetTable<Inte_CRM.CRM_SaleOrder>()
    select new Inte_CRM.CRM_SaleOrder(a)
    {
        Client = new Inte_CRM.Client(a.Client)
        {
            CloudServer = new Inte_CRM.CloudServer
            {
                CloudServerId = a.Client.CloudServer.CloudServerId,
                CloudServerName = a.Client.CloudServer.CloudServerName
            }
        },
        HeavyBuyer = new Inte_CRM.Client
        {
            ClientId = a.Client.ClientId + 10,
            ClientName = a.Client.ClientName + "_heavy",
            CloudServer = new Inte_CRM.CloudServer
            {
                CloudServerId = a.Client.CloudServer.CloudServerId + 10,
                CloudServerName = a.Client.CloudServer.CloudServerName + "_heavy",
            }
        }
    };
r1 = query.ToList();
//SQL=>
//SELECT
//t0.[OrderId] AS [OrderId],
//t0.[OrderNo] AS [OrderNo],
//t0.[Remark] AS [Remark],
//t0.[ClientId] AS [ClientId],
//t1.[ClientId] AS [ClientId1],
//t1.[ClientCode] AS [ClientCode],
//t1.[ClientName] AS [ClientName],
//t1.[State] AS [State],
//t1.[ActiveDate] AS [ActiveDate],
//t1.[CloudServerId] AS [CloudServerId],
//t2.[CloudServerId] AS [CloudServerId1],
//t2.[CloudServerName] AS [CloudServerName],
//t1.[ClientId] + 10 AS [ClientId2],
//t1.[ClientName] + N'_heavy' AS [ClientName1],
//t2.[CloudServerId] + 10 AS [CloudServerId2],
//t2.[CloudServerName] + N'_heavy' AS [CloudServerName1]
//FROM [CRM_SaleOrder] t0
//LEFT JOIN [Bas_Client] t1 ON t0.[ClientId] = t1.[ClientId]
//LEFT JOIN [Sys_CloudServer] t2 ON t1.[CloudServerId] = t2.[CloudServerId]

其它更多示例在源码的 demo 中有详细说明,源码地址:https://github.com/TANZAME/Inte.XFramework

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

【原创】打造基于Dapper的数据访问层的更多相关文章

  1. 自己写的Dapper通用数据访问层

    using Microsoft.Practices.EnterpriseLibrary.Data; using Microsoft.Practices.EnterpriseLibrary.Data.O ...

  2. NET Core 实战 Dapper 扩展数据访问

    NET Core 实战:基于 Dapper 扩展你的数据访问方法 一.前言 在非静态页面的项目开发中,必定会涉及到对于数据库的访问,最开始呢,我们使用 Ado.Net,通过编写 SQL 帮助类帮我们实 ...

  3. 同时支持EF+Dapper的混合仓储,助你快速搭建数据访问层

    背景 17年开始,公司开始向DotNet Core转型,面对ORM工具的选型,当时围绕Dapper和EF发生了激烈的讨论.项目团队更加关注快速交付,他们主张使用EF这种能快速开发的ORM工具:而在线业 ...

  4. 【Hades】ades是一个开源库,基于JPA和Spring构建,通过减少开发工作量显著的改进了数据访问层的实现

    几乎每个应用系统都需要通过访问数据来完成工作.要想使用领域设计方法,你就需要为实体类定义和构建资源库来实现领域对象的持久化.目前开发人员经常使用JPA来实现持久化库.JPA让持久化变得非常容易,但是仍 ...

  5. 使用JDBC构建简单的数据访问层

    本教程的目的是使用Java编写的分离的层去访问数据库中的表,这一层通常称为数据访问层(DAL) 使用DAL的最大好处是通过直接使用一些类似insert()和find()的方法简化了数据库的访问操作,而 ...

  6. 企业级应用架构(三)三层架构之数据访问层的改进以及测试DOM的发布

    在上一篇我们在宏观概要上对DAL层进行了封装与抽象.我们的目的主要有两个:第一,解除BLL层对DAL层的依赖,这一点我们通过定义接口做到了:第二,使我们的DAL层能够支持一切数据访问技术,如Ado.n ...

  7. 【转】在Spring中基于JDBC进行数据访问时怎么控制超时

    http://www.myexception.cn/database/1651797.html 在Spring中基于JDBC进行数据访问时如何控制超时 超时分类 超时根据作用域可做如下层级划分: Tr ...

  8. 数据访问层的改进以及测试DOM的发布

    数据访问层的改进以及测试DOM的发布 在上一篇我们在宏观概要上对DAL层进行了封装与抽象.我们的目的主要有两个:第一,解除BLL层对DAL层的依赖,这一点我们通过定义接口做到了:第二,使我们的DAL层 ...

  9. NHibernate:教你如何搭建数据访问层?

    NHibernate:教你如何搭建数据访问层? 什么是NHibernate NHibernate 是一个基于.net 的针对关系型数据库的对象持久化类库.NHibernate 来源于非常优秀的基于Ja ...

随机推荐

  1. 浅析position:relative position:absolute

    定位一直是WEB标准应用中的难点,如果理不清楚定位那么可能应实现的效果实现不了,实现了的效果可能会走样.如果理清了定位的原理,那定位会让网页实现的更加完美. 定位的定义: 在CSS中关于定位的内容是: ...

  2. iOS \U6b3e转字符串

    -(NSString *)replaceUnicode:(NSString *)unicodeStr { NSString *tempStr1 = [unicodeStr stringByReplac ...

  3. 通过Ollydbg定位私有协议通信明文

    简介:做安全的筒子经常会碰到这样的问题,当向要分析通信协议的时候往往都会有加密通信保护,对于SSL通信我们可以使用SSL劫持,但对于应用层面的加密就显得无能为力了,最好的办法就是调试应用,在应用内部去 ...

  4. Eclipse环境安装C/C++插件CDT和Eclipse安装的插件卸载(删除)

    http://blog.csdn.net/typa01_kk/article/details/49252513

  5. delphi 杀死进程

    http://blog.sina.com.cn/s/blog_554b1f1b0100aygo.html unit Tlhelp323; interface uses  Windows,SysUtil ...

  6. [NHibernate]使用AttributeNHibernate.Mapping.Attributes

    系列文章 [Nhibernate]体系结构 [NHibernate]ISessionFactory配置 [NHibernate]持久化类(Persistent Classes) [NHibernate ...

  7. Ubuntu下,清屏等终端常用命令

    转自:http://blog.csdn.net/gaojinshan/article/details/9314435 # ctrl + l - 清屏 . cLear# ctrl + c - 终止命令. ...

  8. nginx配置rewrite总结

    1.rewrite regex replacement [flag] 2.flag为break时,url重写后,直接使用当前资源,不在执行location里其他语句,完成本次请求,地址栏url不变. ...

  9. android 启动socket 失败:socket(af_inet sock_stream 0) 返回-1

    Android 启动socket 失败:socket(af_inet sock_stream 0) 返回-1 原因权限问题, 应该添加如下权限: <uses-permission android ...

  10. Storm应用系列之——集成Kafka

    本文系原创系列,转载请注明. 原帖地址:http://blog.csdn.net/xeseo 前言 在前面Storm系列之——基本概念一文中,提到过Storm的Spout应该是源源不断的取数据,不能间 ...