【原创】打造基于Dapper的数据访问层
【原创】打造基于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 )。在本框架中,需要解决的主要问题有如下几点:
- 如何生成Dapper查询所需要的TSQL脚本和参数
- 如何将Lambda表达式解析成查询条件
- 如何将Dapper返回的IDataReader转化成DataTable和DataSet
- 如何解决多数据库的问题
--------------------------------------- 华丽丽的分割线 --------------------------------------------
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)
【原创】重复造轮子之高仿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的数据访问层的更多相关文章
- 自己写的Dapper通用数据访问层
using Microsoft.Practices.EnterpriseLibrary.Data; using Microsoft.Practices.EnterpriseLibrary.Data.O ...
- NET Core 实战 Dapper 扩展数据访问
NET Core 实战:基于 Dapper 扩展你的数据访问方法 一.前言 在非静态页面的项目开发中,必定会涉及到对于数据库的访问,最开始呢,我们使用 Ado.Net,通过编写 SQL 帮助类帮我们实 ...
- 同时支持EF+Dapper的混合仓储,助你快速搭建数据访问层
背景 17年开始,公司开始向DotNet Core转型,面对ORM工具的选型,当时围绕Dapper和EF发生了激烈的讨论.项目团队更加关注快速交付,他们主张使用EF这种能快速开发的ORM工具:而在线业 ...
- 【Hades】ades是一个开源库,基于JPA和Spring构建,通过减少开发工作量显著的改进了数据访问层的实现
几乎每个应用系统都需要通过访问数据来完成工作.要想使用领域设计方法,你就需要为实体类定义和构建资源库来实现领域对象的持久化.目前开发人员经常使用JPA来实现持久化库.JPA让持久化变得非常容易,但是仍 ...
- 使用JDBC构建简单的数据访问层
本教程的目的是使用Java编写的分离的层去访问数据库中的表,这一层通常称为数据访问层(DAL) 使用DAL的最大好处是通过直接使用一些类似insert()和find()的方法简化了数据库的访问操作,而 ...
- 企业级应用架构(三)三层架构之数据访问层的改进以及测试DOM的发布
在上一篇我们在宏观概要上对DAL层进行了封装与抽象.我们的目的主要有两个:第一,解除BLL层对DAL层的依赖,这一点我们通过定义接口做到了:第二,使我们的DAL层能够支持一切数据访问技术,如Ado.n ...
- 【转】在Spring中基于JDBC进行数据访问时怎么控制超时
http://www.myexception.cn/database/1651797.html 在Spring中基于JDBC进行数据访问时如何控制超时 超时分类 超时根据作用域可做如下层级划分: Tr ...
- 数据访问层的改进以及测试DOM的发布
数据访问层的改进以及测试DOM的发布 在上一篇我们在宏观概要上对DAL层进行了封装与抽象.我们的目的主要有两个:第一,解除BLL层对DAL层的依赖,这一点我们通过定义接口做到了:第二,使我们的DAL层 ...
- NHibernate:教你如何搭建数据访问层?
NHibernate:教你如何搭建数据访问层? 什么是NHibernate NHibernate 是一个基于.net 的针对关系型数据库的对象持久化类库.NHibernate 来源于非常优秀的基于Ja ...
随机推荐
- 浅析position:relative position:absolute
定位一直是WEB标准应用中的难点,如果理不清楚定位那么可能应实现的效果实现不了,实现了的效果可能会走样.如果理清了定位的原理,那定位会让网页实现的更加完美. 定位的定义: 在CSS中关于定位的内容是: ...
- iOS \U6b3e转字符串
-(NSString *)replaceUnicode:(NSString *)unicodeStr { NSString *tempStr1 = [unicodeStr stringByReplac ...
- 通过Ollydbg定位私有协议通信明文
简介:做安全的筒子经常会碰到这样的问题,当向要分析通信协议的时候往往都会有加密通信保护,对于SSL通信我们可以使用SSL劫持,但对于应用层面的加密就显得无能为力了,最好的办法就是调试应用,在应用内部去 ...
- Eclipse环境安装C/C++插件CDT和Eclipse安装的插件卸载(删除)
http://blog.csdn.net/typa01_kk/article/details/49252513
- delphi 杀死进程
http://blog.sina.com.cn/s/blog_554b1f1b0100aygo.html unit Tlhelp323; interface uses Windows,SysUtil ...
- [NHibernate]使用AttributeNHibernate.Mapping.Attributes
系列文章 [Nhibernate]体系结构 [NHibernate]ISessionFactory配置 [NHibernate]持久化类(Persistent Classes) [NHibernate ...
- Ubuntu下,清屏等终端常用命令
转自:http://blog.csdn.net/gaojinshan/article/details/9314435 # ctrl + l - 清屏 . cLear# ctrl + c - 终止命令. ...
- nginx配置rewrite总结
1.rewrite regex replacement [flag] 2.flag为break时,url重写后,直接使用当前资源,不在执行location里其他语句,完成本次请求,地址栏url不变. ...
- android 启动socket 失败:socket(af_inet sock_stream 0) 返回-1
Android 启动socket 失败:socket(af_inet sock_stream 0) 返回-1 原因权限问题, 应该添加如下权限: <uses-permission android ...
- Storm应用系列之——集成Kafka
本文系原创系列,转载请注明. 原帖地址:http://blog.csdn.net/xeseo 前言 在前面Storm系列之——基本概念一文中,提到过Storm的Spout应该是源源不断的取数据,不能间 ...