Linq to SQL 参考Demo

   1 LINQ to SQL语句(1)之Where
   2  
   3 
   4 Where操作
   5  
   6 
   7 适用场景:实现过滤,查询等功能。
   8 
   9  
  10 
  11 说明:与SQL命令中的Where作用相似,都是起到范围限定也就是过滤作用的,而判断条件就是它后面所接的子句。
  12 
  13  
  14 
  15 Where操作包括3种形式,分别为简单形式、关系条件形式、First()形式。下面分别用实例举例下:
  16 
  17  
  18 
  19 1.简单形式:
  20  
  21 
  22 例如:使用where筛选在伦敦的客户
  23 
  24  
  25 
  26 var q =
  27 
  28   from c in db.Customers
  29 
  30   where c.City == "London"
  31 
  32   select c;
  33 
  34  
  35 
  36 再如:筛选1994 年或之后雇用的雇员:
  37 
  38  
  39 
  40 var q =
  41 
  42   from e in db.Employees
  43 
  44   where e.HireDate >= new DateTime(1994, 1, 1)
  45 
  46   select e;
  47 
  48 2.关系条件形式:
  49  
  50 
  51 筛选库存量在订货点水平之下但未断货的产品:
  52 
  53  
  54 
  55 var q =
  56 
  57   from p in db.Products
  58 
  59   where p.UnitsInStock <= p.ReorderLevel && !p.Discontinued
  60 
  61   select p;
  62 
  63  
  64 
  65 筛选出UnitPrice 大于10 或已停产的产品:
  66 
  67  
  68 
  69 var q =
  70 
  71   from p in db.Products
  72 
  73   where p.UnitPrice > 10m || p.Discontinued
  74 
  75   select p;
  76 
  77  
  78 
  79 下面这个例子是调用两次where以筛选出UnitPrice大于10且已停产的产品。
  80 
  81  
  82 
  83 var q =
  84 
  85   db.Products.Where(p=>p.UnitPrice > 10m).Where(p=>p.Discontinued);
  86 
  87 3.First()形式:
  88  
  89 
  90 返回集合中的一个元素,其实质就是在SQL语句中加TOP (1)。
  91 
  92  
  93 
  94 简单用法:选择表中的第一个发货方。
  95 
  96  
  97 
  98 Shipper shipper = db.Shippers.First();
  99 
 100  
 101 
 102 元素:选择CustomerID 为“BONAP”的单个客户
 103 
 104  
 105 
 106 Customer cust = db.Customers.First(c =>c.CustomerID == "BONAP");
 107 
 108  
 109 
 110 条件:选择运费大于 10.00 的订单:
 111 
 112  
 113 
 114 Order ord = db.Orders.First(o =>o.Freight > 10.00M);
 115 
 116  
 117 
 118  
 119 
 120 LINQ to SQL语句(2)之Select/Distinct
 121  
 122 
 123 [1] Select介绍1
 124 
 125  
 126 
 127 [2] Select介绍2
 128 
 129  
 130 
 131 [3] Select介绍3和 Distinct介绍
 132 
 133  
 134 
 135 Select/Distinct操作符
 136 
 137  
 138 
 139 适用场景:o(∩_∩) o…查询呗。
 140 
 141  
 142 
 143 说明:和SQL命令中的select作用相似但位置不同,查询表达式中的select及所接子句是放在表达式最后并把子句中的变量也就是结果返回回来;延迟。
 144 
 145  
 146 
 147 Select/Distinct操作包括9种形式,分别为简单用 法、匿名类型形式、条件形式、指定类型形式、筛选形式、整形类型形式、嵌套类型形式、本地方法调用形式、Distinct形式。
 148 
 149  
 150 
 151 1.简单用法:
 152  
 153 
 154 这个示例返回仅含客户联系人姓名的序列。
 155 
 156  
 157 
 158 var q =
 159 
 160   from c in db.Customers
 161 
 162   select c.ContactName;
 163 
 164  
 165 
 166 注意:这个语句只是一个声明或者一个描述,并没有真正把数据取出来,只有当你需要该数据的时候,它才会执行这个语句,这就是延迟加载(deferred loading)。如果,在声明的时候就返回的结果集是对象的集合。你可以使用ToList() 或ToArray()方法把查询结果先进行保存,然后再对这个集合进行查询。当然延迟加载(deferred loading)可以像拼接SQL语句那样拼接查询语法,再执行它。
 167 
 168  
 169 
 170 2.匿名类型形式:
 171  
 172 
 173 说明:匿名类型是C#3.0中新特性。其实质是编译器根据我们自定义自动产生一个匿名的类来帮助我们实现临时变量的储存。匿名类型还依赖于另外一个特性:支持根据property来创建对象。比如,var d = new { Name = "s" };编译器自动产生一个有property叫做Name的匿名类,然后按这 个类型分配内存,并初始化对象。但是var d = new {"s"};是编译不 通过的。因为,编译器不知道匿名类中的property的名字。例如stringc = "d";var d = new { c}; 则是可以通过编译的。编译器会创建一个叫 做匿名类带有叫c的property。
 174 
 175  
 176 
 177 例如下例:new {c,ContactName,c.Phone};ContactName和Phone都是在映射文件中定义与表中字 段相对应的property。编译器读取数据并创建对象时,会创建一个匿名类,这个 类有两个属性,为ContactName和Phone,然后根据数据初始化对象。另外编译器 还可以重命名property的名字。
 178 
 179  
 180 
 181 var q =
 182 
 183   from c in db.Customers
 184 
 185   select new {c.ContactName, c.Phone};
 186 
 187  
 188 
 189 上面语句描述:使用 SELECT 和匿名类型返回仅含客户联系人姓名和电话号码的序列
 190 
 191  
 192 
 193 var q =
 194 
 195   from e in db.Employees
 196 
 197   select new
 198 
 199   {
 200 
 201     Name = e.FirstName + " " + e.LastName,
 202 
 203     Phone = e.HomePhone
 204 
 205   };
 206 
 207  
 208 
 209 上面语句描述:使用SELECT和匿名类型返回仅含雇员姓名和电话号码的序列,并将 FirstName和LastName字段合并为一个字段“Name”,此外在所得的序列中将HomePhone字段重命名为Phone。
 210 
 211  
 212 
 213 var q =
 214 
 215   from p in db.Products
 216 
 217   select new
 218 
 219   {
 220 
 221      p.ProductID,
 222 
 223     HalfPrice = p.UnitPrice / 2
 224 
 225   };
 226 
 227  
 228 
 229 上面语句描述:使用SELECT和匿名类型返回所有产品的ID以及 HalfPrice(设置为产品单价除以2所得的值)的序列。
 230 
 231  
 232 
 233 3.条件形式:
 234  
 235 
 236 说明:生成SQL语句为:case when condition then else 237 
 238  
 239 
 240 var q =
 241 
 242   from p in db.Products
 243 
 244   select new
 245 
 246   {
 247 
 248     p.ProductName,
 249 
 250     Availability =
 251 
 252      p.UnitsInStock - p.UnitsOnOrder < 0 ?
 253 
 254     "Out Of Stock" : "In Stock"
 255 
 256   };
 257 
 258  
 259 
 260 上面语句描述:使用SELECT和条件语句返回产品名称和产品供货状态的序列。
 261 
 262  
 263 
 264 4.指定类型形式:
 265  
 266 
 267 说明:该形式返回你自定义类型的对象集。
 268 
 269  
 270 
 271 var q =
 272 
 273   from e in db.Employees
 274 
 275   select new Name
 276 
 277    {
 278 
 279     FirstName = e.FirstName,
 280 
 281     LastName = e.LastName
 282 
 283   };
 284 
 285  
 286 
 287 上面语句描述:使用SELECT和已知类型返回雇员姓名的序列。
 288 
 289  
 290 
 291 5.筛选形式:
 292  
 293 
 294 说明:结合where使用,起到过滤作用。
 295 
 296  
 297 
 298 var q =
 299 
 300   from c in db.Customers
 301 
 302    where c.City == "London"
 303 
 304   select c.ContactName;
 305 
 306  
 307 
 308 上面语句描述:使用SELECT和WHERE返回仅含伦敦客户联系人姓名的序列。
 309 
 310  
 311 
 312 6.shaped形式(整形类型):
 313  
 314 
 315 说明:其select操作使用了匿名对象,而这个匿名对象中,其属性也是个匿名对象。
 316 
 317  
 318 
 319 var q =
 320 
 321   from c in db.Customers
 322 
 323   select new {
 324 
 325     c.CustomerID,
 326 
 327     CompanyInfo = new {c.CompanyName, c.City, c.Country},
 328 
 329     ContactInfo = new {c.ContactName, c.ContactTitle}
 330 
 331   };
 332 
 333  
 334 
 335 语句描述:使用 SELECT 和匿名类型返回有关客户的数据的整形子集。查询顾客的ID和公司信息(公司名称,城市,国家)以及联系信息(联系人和职位)。
 336 
 337  
 338 
 339 7.嵌套类型形式:
 340  
 341 
 342 说明:返回的对象集中的每个对象DiscountedProducts属性中,又包含一个集合。也就是每个对象也是一个集合类。
 343 
 344  
 345 
 346 var q =
 347 
 348   from o in db.Orders
 349 
 350   select new {
 351 
 352      o.OrderID,
 353 
 354     DiscountedProducts =
 355 
 356       from od in o.OrderDetails
 357 
 358       where od.Discount > 0.0
 359 
 360       select od,
 361 
 362     FreeShippingDiscount = o.Freight
 363 
 364   };
 365 
 366  
 367 
 368 语句描述:使用嵌套查询返回所有订单及其OrderID 的序列、打折订单中项目的子序列以及免送货所省下的金额。
 369 
 370  
 371 
 372 8.本地方法调用形式(LocalMethodCall):
 373  
 374 
 375 这个例子在查询中调用本地方法 PhoneNumberConverter将电话号码转换为国际格式。
 376 
 377  
 378 
 379 var q = from c in db.Customers
 380 
 381      where c.Country == "UK" || c.Country == "USA"
 382 
 383      select new
 384 
 385      {
 386 
 387        c.CustomerID,
 388 
 389        c.CompanyName,
 390 
 391        Phone = c.Phone,
 392 
 393        InternationalPhone =
 394 
 395        PhoneNumberConverter(c.Country, c.Phone)
 396 
 397      };
 398 
 399  
 400 
 401 PhoneNumberConverter方法如下:
 402 
 403  
 404 
 405 public string PhoneNumberConverter(stringCountry, string Phone)
 406 
 407 {
 408 
 409   Phone = Phone.Replace(" ", "").Replace(")", ")-");
 410 
 411   switch (Country)
 412 
 413    {
 414 
 415     case "USA":
 416 
 417       return "1- " + Phone;
 418 
 419     case "UK":
 420 
 421        return "44-" + Phone;
 422 
 423     default:
 424 
 425       return Phone;
 426 
 427   }
 428 
 429 }
 430 
 431  
 432 
 433 下面也是使用了这个方法将电话号码转换为国际格式并创建XDocument
 434 
 435  
 436 
 437 XDocument doc = new XDocument(
 438 
 439   new XElement("Customers", from c in db.Customers
 440 
 441        where c.Country == "UK" || c.Country == "USA"
 442 
 443        select (new XElement ("Customer",
 444 
 445            new XAttribute ("CustomerID", c.CustomerID),
 446 
 447            new XAttribute("CompanyName", c.CompanyName),
 448 
 449            new XAttribute("InterationalPhone",
 450 
 451             PhoneNumberConverter(c.Country, c.Phone))
 452 
 453            ))));
 454 
 455 9.Distinct形式:
 456  
 457 
 458 说明:筛选字段中不相同的值。用于查询不重复的结果集。生成SQL语句为:SELECT DISTINCT [City] FROM [Customers]
 459 
 460  
 461 
 462 var q = (
 463 
 464   from c in db.Customers
 465 
 466   select c.City )
 467 
 468   .Distinct();
 469 
 470  
 471 
 472 语句描述:查询顾客覆盖的国家。
 473 
 474  
 475 
 476  
 477 
 478 LINQ to SQL语句(3)之Count/Sum/Min/Max/Avg
 479 [1] Count/Sum讲解
 480 
 481  
 482 
 483 [2] Min讲解
 484 
 485  
 486 
 487 [3] Max讲解
 488 
 489  
 490 
 491 [4] Average和Aggregate讲解
 492 
 493  
 494 
 495 Count/Sum/Min/Max/Avg操作符
 496 
 497  
 498 
 499 适用场景:统计数据吧,比如统计一些数据的个数,求和,最小值,最大值,平均数。
 500 
 501  
 502 
 503 Count
 504 
 505  
 506 
 507 说明:返回集合中的元素个数,返回INT类型;不延迟。生成 SQL语句为:SELECT COUNT(*) FROM
 508 
 509  
 510 
 511 1.简单形式:
 512  
 513 
 514 得到数据库中客户的数量:
 515 
 516  
 517 
 518 var q = db.Customers.Count();
 519 
 520  
 521 
 522 2.带条件形式:
 523  
 524 
 525 得到数据库中未断货产品的数量:
 526 
 527  
 528 
 529 var q = db.Products.Count(p =>!p.Discontinued);
 530 
 531  
 532 
 533 LongCount
 534 
 535  
 536 
 537 说明:返回集合中的元素个数,返回LONG类型;不延迟。对于元素个数较多的集合可视情况可以选用LongCount来统计元素个数,它返回long类型,比较精确。生成 SQL语句为:SELECT COUNT_BIG(*) FROM
 538 
 539  
 540 
 541 var q = db.Customers.LongCount();
 542 
 543  
 544 
 545 Sum
 546 
 547  
 548 
 549 说明:返回集合中数值类型元素之和,集合应为INT类型集合;不延迟。生成SQL语句为:SELECT SUM(…) FROM
 550 
 551  
 552 
 553 1.简单形式:
 554  
 555 
 556 得到所有订单的总运费:
 557 
 558  
 559 
 560 var q = db.Orders.Select(o =>o.Freight).Sum();
 561 
 562  
 563 
 564 2.映射形式:
 565  
 566 
 567 得到所有产品的订货总数:
 568 
 569  
 570 
 571 var q = db.Products.Sum(p =>p.UnitsOnOrder);
 572 
 573 Min
 574 
 575 说明:返回集合中元素的最小值;不延迟。生成SQL语句为:SELECT MIN(…) FROM
 576 
 577 1.简单形式:
 578 
 579 查找任意产品的最低单价:
 580 
 581 var q = db.Products.Select(p => p.UnitPrice).Min();
 582 
 583  
 584 
 585 2.映射形式:
 586 
 587  
 588 
 589 查找任意订单的最低运费:
 590 
 591  
 592 
 593 var q = db.Orders.Min(o => o.Freight);
 594 
 595  
 596 
 597  
 598 
 599 3.元素:
 600  
 601 
 602 查找每个类别中单价最低的产品:
 603 
 604  
 605 
 606 var categories =
 607 
 608   from p in db.Products
 609 
 610   group p by p.CategoryID into g
 611 
 612   select new {
 613 
 614     CategoryID = g.Key,
 615 
 616      CheapestProducts =
 617 
 618       from p2 in g
 619 
 620        where p2.UnitPrice == g.Min(p3 => p3.UnitPrice)
 621 
 622        select p2
 623 
 624   };
 625 
 626 Max
 627 
 628 说明:返回集合中元素的最大值;不延迟。生成SQL语句为:SELECT MAX(…) FROM
 629 
 630 1.简单形式:
 631 查找任意雇员的最近雇用日期:
 632 
 633 var q = db.Employees.Select(e => e.HireDate).Max();
 634 
 635  
 636 
 637 2.映射形式:
 638  
 639 
 640 查找任意产品的最大库存量:
 641 
 642  
 643 
 644 var q = db.Products.Max(p =>p.UnitsInStock);
 645 
 646  
 647 
 648 3.元素:
 649  
 650 
 651 查找每个类别中单价最高的产品:
 652 
 653  
 654 
 655 var categories =
 656 
 657   from p in db.Products
 658 
 659    group p by p.CategoryID into g
 660 
 661   select new {
 662 
 663      g.Key,
 664 
 665     MostExpensiveProducts =
 666 
 667       from p2 in g
 668 
 669       where p2.UnitPrice == g.Max(p3 => p3.UnitPrice)
 670 
 671       select p2
 672 
 673   };
 674 
 675 Average
 676 
 677 说明:返回集合中的数值类型元素的平均值。集合应为数字类型集合,其返回值类型为double;不延迟。生成SQL语句为:SELECT AVG(…) FROM
 678 
 679 1.简单形式:
 680 得到所有订单的平均运费:
 681 
 682 var q = db.Orders.Select(o =>o.Freight).Average();
 683 
 684  
 685 
 686 2.映射形式:
 687  
 688 
 689 得到所有产品的平均单价:
 690 
 691  
 692 
 693 var q = db.Products.Average(p => p.UnitPrice);
 694 
 695  
 696 
 697 3.元素:
 698  
 699 
 700 查找每个类别中单价高于该类别平均单价的产品:
 701 
 702  
 703 
 704 var categories =
 705 
 706   from p in db.Products
 707 
 708   group p by p.CategoryID into g
 709 
 710   select new {
 711 
 712     g.Key,
 713 
 714     ExpensiveProducts =
 715 
 716       from p2 in g
 717 
 718       where p2.UnitPrice > g.Average (p3 => p3.UnitPrice)
 719 
 720       select p2
 721 
 722   };
 723 
 724  
 725 
 726 Aggregate
 727 
 728  
 729 
 730 说明:根据输入的表达式获取聚合值;不延迟。即是说:用一个种子值与当前元素通过指定的函数来进行对比来遍历集合中的元素,符合条件的元素保留下来。如果没有指定种子值的话,种子值默认为集合的第一个元素。
 731 
 732  
 733 
 734  
 735 
 736 LINQ to SQL语句(4)之Join
 737 Join操作符
 738  
 739 
 740 适用场景:在我们表关系中有一对一关系,一对多关系,多对多关系等。对各个表之间的关系,就用这些实现对多个表的操作。
 741 
 742  
 743 
 744 说明:在Join操作中,分别为Join(Join查询), SelectMany(Select一对多选择) 和GroupJoin(分组Join查询)。
 745 
 746  
 747 
 748 该扩展方法对两个序列中键匹配的元素进行inner join操作
 749 
 750  
 751 
 752 SelectMany
 753 
 754  
 755 
 756 说明:我们在写查询语句时,如果被翻译成SelectMany需要满足2个条件。1:查询语句中没有join和into,2:必须出现EntitySet。在我们表关系中有一对一关系,一对多关系,多对多关系等,下面分别介绍一下。
 757 
 758  
 759 
 760 1.一对多关系(1 to Many):
 761  
 762 
 763 var q =
 764 
 765   from c in db.Customers
 766 
 767   from o in c.Orders
 768 
 769   where c.City == "London"
 770 
 771   select o;
 772 
 773  
 774 
 775 语句描述:Customers与Orders是一对多关系。即Orders在Customers类中以 EntitySet形式出现。所以第二个from是从c.Orders而不是db.Orders里进行筛选。这个例子在From子句中使用外键导航选择伦敦客户的所有订单。
 776 
 777  
 778 
 779 var q =
 780 
 781   from p in db.Products
 782 
 783   where p.Supplier.Country == "USA" &&p.UnitsInStock == 0
 784 
 785   select p;
 786 
 787  
 788 
 789 语句描述:这一句使用了 p.Supplier.Country条件,间接关联了Supplier表。这个例子在Where子句中使用外键导航筛选其供应商在美国且缺货的产品。生成SQL语句为:
 790 
 791  
 792 
 793 SELECT [t0].[ProductID],[t0].[ProductName], [t0]. [SupplierID],
 794 
 795 [t0].[CategoryID],[t0].[QuantityPerUnit],[t0].[UnitPrice],
 796 
 797 [t0].[UnitsInStock],[t0].[UnitsOnOrder],[t0]. [ReorderLevel],
 798 
 799 [t0].[Discontinued] FROM [dbo].[Products]AS [t0]
 800 
 801 LEFT OUTER JOIN [dbo].[Suppliers] AS [t1]ON
 802 
 803 [t1]. [SupplierID] = [t0].[SupplierID]
 804 
 805 WHERE ([t1].[Country] = @p0) AND([t0].[UnitsInStock] = @p1)
 806 
 807 -- @p0: Input NVarChar (Size = 3; Prec = 0;Scale = 0) [USA]
 808 
 809 -- @p1: Input Int (Size = 0; Prec = 0;Scale = 0) [0]
 810 
 811  
 812 
 813 2.多对多关系(Many to Many):
 814  
 815 
 816 var q =
 817 
 818   from e in db.Employees
 819 
 820   from et in e.EmployeeTerritories
 821 
 822   where e.City == "Seattle"
 823 
 824   select new
 825 
 826   {
 827 
 828     e.FirstName,
 829 
 830      e.LastName,
 831 
 832     et.Territory.TerritoryDescription
 833 
 834   };
 835 
 836  
 837 
 838 说明:多对多关系一般会涉及三个表(如果有一个表是自关联的,那有可能只有2个表)。这一句语句涉及Employees, EmployeeTerritories, Territories三个表。它们的关系是1:M:1。Employees 和Territories没有很明确的关系。
 839 
 840  
 841 
 842 语句描述:这个例子在From子句中使用外键导航筛选在西雅图的雇员,同时列出其所在地区。这条生成SQL语句为:
 843 
 844  
 845 
 846 SELECT [t0].[FirstName], [t0].[LastName],[t2]. [TerritoryDescription]
 847 
 848 FROM [dbo].[Employees] AS [t0] CROSS JOIN[dbo].[EmployeeTerritories]
 849 
 850 AS [t1] INNER JOIN [dbo]. [Territories] AS[t2] ON
 851 
 852 [t2].[TerritoryID] = [t1].[TerritoryID]
 853 
 854 WHERE ([t0].[City] = @p0) AND([t1].[EmployeeID] = [t0]. [EmployeeID])
 855 
 856 -- @p0: Input NVarChar (Size = 7; Prec = 0;Scale = 0) [Seattle]
 857 
 858  
 859 
 860  
 861 
 862 3.自联接关系:
 863  
 864 
 865 var q =
 866 
 867   from e1 in db.Employees
 868 
 869   from e2 in e1.Employees
 870 
 871   where e1.City == e2.City
 872 
 873   select new {
 874 
 875     FirstName1 = e1.FirstName, LastName1 = e1.LastName,
 876 
 877     FirstName2 = e2.FirstName, LastName2 = e2.LastName,
 878 
 879     e1.City
 880 
 881   };
 882 
 883  
 884 
 885 语句描述:这个例子在select 子句中使用外键导航筛选成对的雇员,每对中一个雇员隶属于另一个雇员,且两个雇员都来自相同城市。生成SQL语句为:
 886 
 887  
 888 
 889 SELECT [t0].[FirstName] AS [FirstName1],[t0].[LastName] AS
 890 
 891 [LastName1],[t1].[FirstName] AS[FirstName2], [t1].[LastName] AS
 892 
 893 [LastName2],[t0].[City] FROM[dbo].[Employees] AS [t0],
 894 
 895 [dbo].[Employees] AS [t1] WHERE([t0].[City] = [t1]. [City]) AND
 896 
 897 ([t1].[ReportsTo] = [t0].[EmployeeID])
 898 
 899 GroupJoin
 900 
 901  
 902 
 903 像上面所说的,没有join和into,被翻译成 SelectMany,同时有join和into时,那么就被翻译为GroupJoin。在这里into的概念是对其结果进行重新命名。
 904 
 905  
 906 
 907 1.双向联接(Two way join):
 908  
 909 
 910 此示例显式联接两个表并从这两个表投影出结果:
 911 
 912  
 913 
 914 var q =
 915 
 916    from c in db.Customers
 917 
 918   join o in db.Orders on c.CustomerID
 919 
 920   equals o.CustomerID into orders
 921 
 922   select new
 923 
 924    {
 925 
 926     c.ContactName,
 927 
 928     OrderCount = orders.Count ()
 929 
 930   };
 931 
 932  
 933 
 934 说明:在一对多关系中,左边是1,它每条记录为c(from c in db.Customers),右边是Many,其每条记录叫做o ( join o in db.Orders ),每对应左边的一个c,就会有一组o,那这一组o,就叫做orders, 也就是说,我们把一组o命名为orders,这就是into用途。这也就是为什么在select语句中,orders可以调用聚合函数Count。在T-SQL中,使用其内嵌的T- SQL返回值作为字段值。如图所示:
 935 
 936  
 937 
 938  
 939 
 940  
 941 
 942 生成SQL语句为:
 943 
 944  
 945 
 946 SELECT [t0].[ContactName], (
 947 
 948   SELECT COUNT(*)
 949 
 950   FROM [dbo].[Orders] AS [t1]
 951 
 952    WHERE [t0].[CustomerID] = [t1].[CustomerID]
 953 
 954 ) AS [OrderCount]
 955 
 956 FROM [dbo].[Customers] AS [t0]
 957 
 958  
 959 
 960 2.三向联接(There way join):
 961  
 962 
 963 此示例显式联接三个表并分别从每个表投影出结果:
 964 
 965  
 966 
 967 var q =
 968 
 969   from c in db.Customers
 970 
 971   join o in db.Orders on c.CustomerID
 972 
 973   equals o.CustomerID into ords
 974 
 975   join e in db.Employees on c.City
 976 
 977   equals e.City into emps
 978 
 979   select new
 980 
 981   {
 982 
 983     c.ContactName,
 984 
 985     ords = ords.Count(),
 986 
 987     emps = emps.Count()
 988 
 989   };
 990 
 991  
 992 
 993 生成SQL语句为:
 994 
 995  
 996 
 997 SELECT [t0]. [ContactName], (
 998 
 999   SELECT COUNT(*)
1000 
1001   FROM [dbo].[Orders] AS [t1]
1002 
1003   WHERE [t0].[CustomerID] = [t1].[CustomerID]
1004 
1005 ) AS [ords], (
1006 
1007 SELECT COUNT(*)
1008 
1009   FROM [dbo].[Employees] AS [t2]
1010 
1011   WHERE [t0].[City] = [t2].[City]
1012 
1013 ) AS [emps]
1014 
1015 FROM [dbo].[Customers] AS [t0]
1016 
1017  
1018 
1019 3.左外部联接(Left Outer Join):
1020  
1021 
1022 此示例说明如何通过使用此示例说明如何通过使用 DefaultIfEmpty() 获取左外部联接。在雇员没有订单时,DefaultIfEmpty()方法返回null:
1023 
1024  
1025 
1026 var q =
1027 
1028   from e in db.Employees
1029 
1030    join o in db.Orders on e equals o.Employee into ords
1031 
1032   from o in ords.DefaultIfEmpty()
1033 
1034   select new
1035 
1036   {
1037 
1038      e.FirstName,
1039 
1040     e.LastName,
1041 
1042     Order = o
1043 
1044    };
1045 
1046  
1047 
1048 说明:以Employees左表,Orders右表,Orders 表中为空时,用null值填充。Join的结果重命名ords,使用DefaultIfEmpty()函数对其再次查询。其最后的结果中有个Order,因为from o in ords.DefaultIfEmpty() 是对 ords组再一次遍历,所以,最后结果中的Order并不是一个集合。但是,如果没有from o in ords.DefaultIfEmpty() 这句,最后的select语句写成selectnew { e.FirstName, e.LastName, Order = ords }的话,那么Order就是一个集合。
1049 
1050  
1051 
1052 4.投影的Let赋值(Projectedlet assignment):
1053  
1054 
1055 说明:let语句是重命名。let位于第一个from和select语句之间。
1056 
1057  
1058 
1059 这个例子从联接投影出最终“Let”表达式:
1060 
1061  
1062 
1063 var q =
1064 
1065   from c in db.Customers
1066 
1067   join o in db.Orders on c.CustomerID
1068 
1069    equals o.CustomerID into ords
1070 
1071   let z = c.City + c.Country
1072 
1073   from o in ords
1074 
1075   select new
1076 
1077   {
1078 
1079      c.ContactName,
1080 
1081     o.OrderID,
1082 
1083     z
1084 
1085   };
1086 
1087  
1088 
1089 5.组合键(Composite Key):
1090  
1091 
1092 这个例子显示带有组合键的联接:
1093 
1094  
1095 
1096 var q =
1097 
1098   from o in db.Orders
1099 
1100   from p in db.Products
1101 
1102   join d in db.OrderDetails
1103 
1104     on new
1105 
1106     {
1107 
1108       o.OrderID,
1109 
1110        p.ProductID
1111 
1112     } equals
1113 
1114       new
1115 
1116       {
1117 
1118         d.OrderID,
1119 
1120          d.ProductID
1121 
1122       }
1123 
1124     into details
1125 
1126   from d in details
1127 
1128   select new
1129 
1130   {
1131 
1132     o.OrderID,
1133 
1134     p.ProductID,
1135 
1136     d.UnitPrice
1137 
1138   };
1139 
1140  
1141 
1142 说明:使用三个表,并且用匿名类来说明:使用三个表,并且用匿名类来表示它们之间的关系。它们之间的关系不能用一个键描述清楚,所以用匿名类,来表示组合键。还有一种是两个表之间是用组合键表示关系的,不需要使用匿名类。
1143 
1144  
1145 
1146 6.可为null/不可为null的键关系 (Nullable/Nonnullable Key Relationship):
1147  
1148 
1149 这个实例显示如何构造一侧可为 null 而另一侧不可为 null 的联接:
1150 
1151  
1152 
1153 var q =
1154 
1155    from o in db.Orders
1156 
1157   join e in db.Employees
1158 
1159     on o.EmployeeID equals
1160 
1161     (int?)e.EmployeeID into emps
1162 
1163   from e in emps
1164 
1165   select new
1166 
1167   {
1168 
1169      o.OrderID,
1170 
1171     e.FirstName
1172 
1173   };
1174 
1175  
1176 
1177 LINQ to SQL语句(5)之Order By
1178 Order By操作
1179  
1180 
1181 适用场景:对查询出的语句进行排序,比如按时间排序等等。
1182 
1183  
1184 
1185 说明:按指定表达式对集合排序;延迟,:按指定表达式对集合排序;延迟,默认是升序,加上descending表示降序,对应的扩展方法是 OrderBy和OrderByDescending
1186 
1187  
1188 
1189 1.简单形式
1190  
1191 
1192 这个例子使用 orderby 按雇用日期对雇员进行排序:
1193 
1194  
1195 
1196 var q =
1197 
1198   from e in db.Employees
1199 
1200   orderby e.HireDate
1201 
1202   select e;
1203 
1204  
1205 
1206 说明:默认为升序
1207 
1208  
1209 
1210 2.带条件形式
1211  
1212 
1213 注意:Where 和Order By的顺序并不重要。而在T-SQL中,Where和Order By有严格的位置限制。
1214 
1215  
1216 
1217 var q =
1218 
1219   from o in db.Orders
1220 
1221   where o.ShipCity == "London"
1222 
1223   orderby o.Freight
1224 
1225    select o;
1226 
1227  
1228 
1229 语句描述:使用where和orderby按运费进行排序。
1230 
1231  
1232 
1233 3.降序排序
1234  
1235 
1236 var q =
1237 
1238   from p in db.Products
1239 
1240   orderby p.UnitPrice descending
1241 
1242   select p;
1243 
1244  
1245 
1246  
1247 
1248 4.ThenBy
1249  
1250 
1251 语句描述:使用复合的 orderby 对客户进行排序,进行排序:
1252 
1253  
1254 
1255 var q =
1256 
1257   from c in db.Customers
1258 
1259   orderby c.City, c.ContactName
1260 
1261   select c;
1262 
1263  
1264 
1265 说明:按多个表达式进行排序,例如先按City排序,当City相同时,按ContactName排序。这一句用Lambda表达式像这样写:
1266 
1267  
1268 
1269 var q =
1270 
1271   .OrderBy(c => c.City)
1272 
1273   .ThenBy(c => c.ContactName).ToList();
1274 
1275  
1276 
1277 在T-SQL中没有 ThenBy语句,其依然翻译为OrderBy,所以也可以用下面语句来表达:
1278 
1279  
1280 
1281 var q =
1282 
1283   db.Customers
1284 
1285   .OrderBy(c => c.ContactName)
1286 
1287   .OrderBy(c => c.City).ToList ();
1288 
1289  
1290 
1291 所要注意的是,多个OrderBy操作时,级连方式是按逆序。对于降序的,用相应的降序操作符替换即可。
1292 
1293  
1294 
1295 var q =
1296 
1297    db.Customers
1298 
1299   .OrderByDescending(c => c.City)
1300 
1301   .ThenByDescending(c => c.ContactName).ToList();
1302 
1303  
1304 
1305 需要说明的是,OrderBy操作,不支持按type排序,也不支持匿名类。比如
1306 
1307  
1308 
1309 var q =
1310 
1311   db.Customers
1312 
1313   .OrderBy(c => new
1314 
1315   {
1316 
1317     c.City,
1318 
1319     c.ContactName
1320 
1321   }).ToList();
1322 
1323  
1324 
1325 会被抛出异常。错误是前面的操作有匿名类,再跟OrderBy时,比较的是类别。比如
1326 
1327  
1328 
1329 var q =
1330 
1331    db.Customers
1332 
1333   .Select(c => new
1334 
1335   {
1336 
1337      c.City,
1338 
1339     c.Address
1340 
1341   })
1342 
1343   .OrderBy(c => c).ToList();
1344 
1345  
1346 
1347 如果你想使用OrderBy(c => c),其前提条件是,前面步骤中,所产生的对象的类别必须为C#语言的基本类型。比如下句,这里 City为string类型。
1348 
1349  
1350 
1351 var q =
1352 
1353   db.Customers
1354 
1355    .Select(c => c.City)
1356 
1357   .OrderBy(c => c).ToList ();
1358 
1359  
1360 
1361  
1362 
1363 5.ThenByDescending
1364  
1365 
1366 这两个扩展方式都是用在 OrderBy/OrderByDescending之后的,第一个ThenBy/ThenByDescending扩展方法 作为第二位排序依据,第二个ThenBy/ThenByDescending则作为第三位排序依据 ,以此类推
1367 
1368  
1369 
1370 var q =
1371 
1372   from o in db.Orders
1373 
1374    where o.EmployeeID == 1
1375 
1376   orderby o.ShipCountry, o.Freight descending
1377 
1378   select o;
1379 
1380  
1381 
1382 语句描述:使用orderby先按发往国家再按运费从高到低的顺序对 EmployeeID 1 的订单进行排序。
1383 
1384  
1385 
1386 6. 带GroupBy形式
1387  
1388 
1389 var q =
1390 
1391   from p in db.Products
1392 
1393    group p by p.CategoryID into g
1394 
1395   orderby g.Key
1396 
1397   select new {
1398 
1399     g.Key,
1400 
1401     MostExpensiveProducts =
1402 
1403       from p2 in g
1404 
1405       where p2.UnitPrice == g.Max(p3 => p3.UnitPrice)
1406 
1407       select p2
1408 
1409   };
1410 
1411  
1412 
1413 语句描述:使用orderby、Max 和 Group By 得出每种类别中单价最高的产品,并按 CategoryID 对这组产品进行排序。
1414 
1415  
1416 
1417 LINQ to SQL语句(6)之GroupBy/Having
1418 Group By/Having操作符
1419  
1420 
1421 适用场景:分组数据,为我们查找数据缩小范围。
1422 
1423  
1424 
1425 说明:分配并返回对传入参数进行分组操作后的可枚举对象。分组;延迟
1426 
1427  
1428 
1429 1.简单形式:
1430  
1431 
1432 var q =
1433 
1434   from p in db.Products
1435 
1436   group p by p.CategoryID into g
1437 
1438   select g;
1439 
1440  
1441 
1442 语句描述:使用Group By按CategoryID划分产品。
1443 
1444  
1445 
1446 说明:from p in db.Products 表示从表中将产品对象取出来。group p by p.CategoryID into g表示对p按CategoryID字段归类。其结果命名为g,一旦重 新命名,p的作用域就结束了,所以,最后select时,只能select g。当然,也不必重新命名可以这样写:
1447 
1448  
1449 
1450 var q =
1451 
1452   from p in db.Products
1453 
1454   group p by p.CategoryID;
1455 
1456  
1457 
1458 我们用示意图表示:
1459 
1460  
1461 
1462  
1463 
1464 如果想遍历某类别中所有记录,这样:
1465 
1466  
1467 
1468 foreach (var gp in q)
1469 
1470 {
1471 
1472   if (gp.Key == 2)
1473 
1474   {
1475 
1476      foreach (var item in gp)
1477 
1478     {
1479 
1480       //do something
1481 
1482     }
1483 
1484   }
1485 
1486 }
1487 
1488  
1489 
1490 2.Select匿名类:
1491  
1492 
1493 var q =
1494 
1495   from p in db.Products
1496 
1497   group p by p.CategoryID into g
1498 
1499   select new { CategoryID = g.Key, g };
1500 
1501  
1502 
1503 说明:在这句LINQ语句中,有2个property:CategoryID和g。这个匿名类,其实质是对返回结果集重新进行了包装。把g的property封装成一个完整的分组。如下图所示:
1504 
1505  
1506 
1507  
1508 
1509 如果想遍历某匿名类中所有记录,要这么做:
1510 
1511  
1512 
1513 foreach (var gp in q)
1514 
1515 {
1516 
1517   if (gp.CategoryID == 2)
1518 
1519   {
1520 
1521     foreach (var item in gp.g)
1522 
1523     {
1524 
1525       //do something
1526 
1527     }
1528 
1529   }
1530 
1531 }
1532 
1533  
1534 
1535 3.最大值
1536  
1537 
1538 var q =
1539 
1540   from p in db.Products
1541 
1542   group p by p.CategoryID into g
1543 
1544   select new {
1545 
1546     g.Key,
1547 
1548     MaxPrice = g.Max(p => p.UnitPrice)
1549 
1550   };
1551 
1552  
1553 
1554 语句描述:使用Group By和Max查找每个CategoryID的最高单价。
1555 
1556  
1557 
1558 说明:先按CategoryID归类,判断各个分类产品中单价最大的 Products。取出CategoryID值,并把UnitPrice值赋给MaxPrice。
1559 
1560  
1561 
1562 4.最小值
1563  
1564 
1565 var q =
1566 
1567   from p in db.Products
1568 
1569   group p by p.CategoryID into g
1570 
1571   select new {
1572 
1573     g.Key,
1574 
1575     MinPrice = g.Min(p => p.UnitPrice)
1576 
1577   };
1578 
1579  
1580 
1581 语句描述:使用Group By和Min查找每个CategoryID的最低单价。
1582 
1583  
1584 
1585 说明:先按CategoryID归类,判断各个分类产品中单价最小的 Products。取出CategoryID值,并把UnitPrice值赋给MinPrice。
1586 
1587  
1588 
1589 5.平均值
1590  
1591 
1592 var q =
1593 
1594   from p in db.Products
1595 
1596   group p by p.CategoryID into g
1597 
1598   select new {
1599 
1600     g.Key,
1601 
1602     AveragePrice = g.Average(p => p.UnitPrice)
1603 
1604   };
1605 
1606  
1607 
1608 语句描述:使用Group By和Average得到每个CategoryID的平均单价。
1609 
1610  
1611 
1612 说明:先按CategoryID归类,取出CategoryID值和各个分类产品中单价的平均值。
1613 
1614  
1615 
1616 6.求和
1617  
1618 
1619 var q =
1620 
1621   from p in db.Products
1622 
1623   group p by p.CategoryID into g
1624 
1625   select new {
1626 
1627     g.Key,
1628 
1629     TotalPrice = g.Sum(p => p.UnitPrice)
1630 
1631   };
1632 
1633  
1634 
1635 语句描述:使用Group By和Sum得到每个CategoryID 的单价总计。
1636 
1637  
1638 
1639 说明:先按CategoryID归类,取出 CategoryID值和各个分类产品中单价的总和。
1640 
1641  
1642 
1643 7.计数
1644  
1645 
1646 var q =
1647 
1648   from p in db.Products
1649 
1650   group p by p.CategoryID into g
1651 
1652   select new {
1653 
1654     g.Key,
1655 
1656     NumProducts = g.Count()
1657 
1658   };
1659 
1660  
1661 
1662 语句描述:使用Group By和Count得到每个CategoryID中产品的数量。
1663 
1664  
1665 
1666 说明:先按CategoryID归类,取出 CategoryID值和各个分类产品的数量。
1667 
1668  
1669 
1670 8.带条件计数
1671  
1672 
1673 var q =
1674 
1675   from p in db.Products
1676 
1677   group p by p.CategoryID into g
1678 
1679   select new {
1680 
1681     g.Key,
1682 
1683     NumProducts = g.Count(p => p.Discontinued)
1684 
1685   };
1686 
1687  
1688 
1689 语句描述:使用Group By和Count得到每个CategoryID中断货产品的数量。
1690 
1691  
1692 
1693 说明:先按 CategoryID归类,取出CategoryID值和各个分类产品的断货数量。Count函数里,使用了Lambda表达式,Lambda表达式中的p,代表这个组里的一个元素或对象,即某一个产品。
1694 
1695  
1696 
1697 9.Where限制
1698  
1699 
1700 var q =
1701 
1702   from p in db.Products
1703 
1704   group p by p.CategoryID into g
1705 
1706   where g.Count() >= 10
1707 
1708   select new {
1709 
1710     g.Key,
1711 
1712     ProductCount = g.Count()
1713 
1714   };
1715 
1716  
1717 
1718 语句描述:根据产品的―ID分组,查询产品数量大于10的ID和产品数量。这个示例在Group By子句后使用Where子句查找所有至少有10种产品的类别。
1719 
1720  
1721 
1722 说明:在翻译成SQL 语句时,在最外层嵌套了Where条件。
1723 
1724  
1725 
1726 10.多列(Multiple Columns)
1727  
1728 
1729 var categories =
1730 
1731   from p in db.Products
1732 
1733    group p by new
1734 
1735   {
1736 
1737     p.CategoryID,
1738 
1739      p.SupplierID
1740 
1741   }
1742 
1743     into g
1744 
1745     select new
1746 
1747       {
1748 
1749         g.Key,
1750 
1751         g
1752 
1753       };
1754 
1755  
1756 
1757 语句描述:使用Group By按CategoryID和 SupplierID将产品分组。
1758 
1759  
1760 
1761 说明:既按产品的分类,又按供应商分类。在 by后面,new出来一个匿名类。这里,Key其实质是一个类的对象,Key包含两个 Property:CategoryID、SupplierID。用g.Key.CategoryID可以遍历CategoryID 的值。
1762 
1763  
1764 
1765 11.表达式(Expression)
1766  
1767 
1768 var categories =
1769 
1770    from p in db.Products
1771 
1772   group p by new { Criterion = p.UnitPrice > 10 } into g
1773 
1774   select g;
1775 
1776  
1777 
1778 语句描述:使用Group By返回两个产品序列。第一个序列包含单价大于10的产品。第二个序列包含单价小于或等于10的产品。
1779 
1780  
1781 
1782 说明:按产品单价是否大于10分类。其结果分为两类,大于的是一类,小于及等于为另一类。
1783 
1784  
1785 
1786 LINQ to SQL语句(7)之Exists/In/Any/All/Contains
1787 Exists/In/Any/All/Contains操作符
1788  
1789 
1790 适用场景:用于判断集合中元素,进一步缩小范围。
1791 
1792  
1793 
1794 Any
1795  
1796 
1797 说明:用于判断集合中是否有元素满足某一条件;不延迟。(若条件为空,则集合只要不为空就返回True,否则为 False)。有2种形式,分别为简单形式和带条件形式。
1798 
1799  
1800 
1801 1.简单形式:
1802  
1803 
1804 仅返回没有订单的客户:
1805 
1806  
1807 
1808 var q =
1809 
1810   from c in db.Customers
1811 
1812   where !c.Orders.Any()
1813 
1814   select c;
1815 
1816  
1817 
1818 生成SQL语句为:
1819 
1820  
1821 
1822 SELECT [t0].[CustomerID],[t0].[CompanyName], [t0].[ContactName],
1823 
1824 [t0].[ContactTitle], [t0].[Address],[t0].[City], [t0].[Region],
1825 
1826 [t0].[PostalCode], [t0].[Country],[t0].[Phone], [t0].[Fax]
1827 
1828 FROM [dbo].[Customers] AS [t0]
1829 
1830 WHERE NOT (EXISTS(
1831 
1832   SELECT NULL AS [EMPTY] FROM [dbo].[Orders] AS [t1]
1833 
1834   WHERE [t1].[CustomerID] = [t0]. [CustomerID]
1835 
1836   ))
1837 
1838  
1839 
1840 2.带条件形式:
1841  
1842 
1843 仅返回至少有一种产品断货的类别:
1844 
1845  
1846 
1847 var q =
1848 
1849   from c in db.Categories
1850 
1851   where c.Products.Any(p => p.Discontinued)
1852 
1853   select c;
1854 
1855  
1856 
1857 生成SQL语句为:
1858 
1859  
1860 
1861 SELECT [t0]. [CategoryID],[t0].[CategoryName], [t0].[Description],
1862 
1863 [t0]. [Picture] FROM [dbo].[Categories] AS[t0]
1864 
1865 WHERE EXISTS(
1866 
1867    SELECT NULL AS [EMPTY] FROM [dbo].[Products] AS [t1]
1868 
1869   WHERE ([t1].[Discontinued] = 1) AND
1870 
1871   ([t1].[CategoryID] = [t0]. [CategoryID])
1872 
1873   )
1874 
1875 All
1876 说明:用于判断集合中所有元素是否都满足某一条件;不延迟1.带条件形式
1877 
1878  
1879 
1880 var q =
1881 
1882   from c in db.Customers
1883 
1884   where c.Orders.All(o => o.ShipCity == c.City)
1885 
1886   select c;
1887 
1888  
1889 
1890 语句描述:这个例子返回所有订单都运往其所在城市的客户或未下订单的客户。
1891 
1892  
1893 
1894 Contains
1895  
1896 
1897 说明:用于判断集合中是否包含有某一元素;不延迟。它是对两个序列进行连接操作的。
1898 
1899  
1900 
1901 string[] customerID_Set =
1902 
1903   new string[] { "AROUT", "BOLID","FISSA" };
1904 
1905 var q = (
1906 
1907   from o in db.Orders
1908 
1909   where customerID_Set.Contains(o.CustomerID)
1910 
1911   select o).ToList ();
1912 
1913  
1914 
1915 语句描述:查找"AROUT", "BOLID""FISSA" 这三个客户的订单。先定义了一个数组,在LINQ to SQL中使用Contains,数组中包含了所有的CustomerID,即返回结果中,所有的 CustomerID都在这个集合内。也就是in。你也可以把数组的定义放在LINQ to SQL语句里。比如:
1916 
1917  
1918 
1919 var q = (
1920 
1921   from o in db.Orders
1922 
1923   where (
1924 
1925   new string[] { "AROUT", "BOLID","FISSA" })
1926 
1927   .Contains (o.CustomerID)
1928 
1929   select o).ToList();
1930 
1931 Not Contains则取反:
1932 
1933 var q = (
1934 
1935   from o in db.Orders
1936 
1937   where !(
1938 
1939   new string[] { "AROUT", "BOLID","FISSA" })
1940 
1941   .Contains(o.CustomerID)
1942 
1943   select o).ToList();
1944 
1945  
1946 
1947 1.包含一个对象:
1948  
1949 
1950 var order = (from o in db.Orders
1951 
1952        where o.OrderID == 10248
1953 
1954        select o).First();
1955 
1956 var q = db.Customers.Where(p =>p.Orders.Contains(order)).ToList();
1957 
1958 foreach (var cust in q)
1959 
1960 {
1961 
1962   foreach (var ord in cust.Orders)
1963 
1964   {
1965 
1966     //do something
1967 
1968   }
1969 
1970 }
1971 
1972  
1973 
1974 语句描述:这个例子使用Contain查找哪个客户包含OrderID为10248的订单。
1975 
1976  
1977 
1978 2.包含多个值:
1979  
1980 
1981 string[] cities =
1982 
1983   new string[] { "Seattle", "London","Vancouver", "Paris" };
1984 
1985 var q = db.Customers.Where(p=>cities.Contains(p.City)).ToList();
1986 
1987  
1988 
1989 语句描述:这个例子使用Contains查找其所在城市为西雅图、伦敦、巴黎或温哥华的客户。
1990 
1991  
1992 
1993  
1994 
1995 LINQ to SQL语句(8)之Concat/Union/Intersect/Except
1996 Concat/Union/Intersect/Except操作
1997  
1998 
1999 适用场景:对两个集合的处理,例如追加、合并、取相同项、相交项等等。
2000 
2001  
2002 
2003 Concat(连接)
2004  
2005 
2006 说明:连接不同的集合,不会自动过滤相同项;延迟。
2007 
2008  
2009 
2010 1.简单形式:
2011 var q = (
2012 
2013      from c in db.Customers
2014 
2015      select c.Phone
2016 
2017     ).Concat(
2018 
2019      from c in db.Customers
2020 
2021      select c.Fax
2022 
2023     ).Concat(
2024 
2025      from e in db.Employees
2026 
2027      select e.HomePhone
2028 
2029     );
2030 
2031  
2032 
2033 语句描述:返回所有消费者和雇员的电话和传真。
2034 
2035  
2036 
2037 2.复合形式:
2038 var q = (
2039 
2040      from c in db.Customers
2041 
2042      select new
2043 
2044      {
2045 
2046        Name = c.CompanyName,
2047 
2048        c.Phone
2049 
2050      }
2051 
2052      ).Concat(
2053 
2054      from e in db.Employees
2055 
2056      select new
2057 
2058      {
2059 
2060        Name = e.FirstName + " " + e.LastName,
2061 
2062        Phone = e.HomePhone
2063 
2064      }
2065 
2066     );
2067 
2068  
2069 
2070 语句描述:返回所有消费者和雇员的姓名和电话。
2071 
2072  
2073 
2074 Union(合并)
2075  
2076 
2077 说明:连接不同的集合,自动过滤相同项;延迟。即是将两个集合进行合并操作,过滤相同的项。
2078 
2079  
2080 
2081 var q = (
2082 
2083      from c in db.Customers
2084 
2085      select c.Country
2086 
2087     ).Union(
2088 
2089      from e in db.Employees
2090 
2091      select e.Country
2092 
2093     );
2094 
2095  
2096 
2097 语句描述:查询顾客和职员所在的国家。
2098 
2099  
2100 
2101 Intersect(相交)
2102  
2103 
2104 说明:取相交项;延迟。即是获取不同集合的相同项(交集)。即先遍历第一个集合,找出所有唯一的元素,然后遍历第二个集合,并将每个元素与前面找出的元素作对比,返回所有在两个集合内都出现的元素。
2105 
2106  
2107 
2108 var q = (
2109 
2110      from c in db.Customers
2111 
2112      select c.Country
2113 
2114     ).Intersect (
2115 
2116      from e in db.Employees
2117 
2118      select e.Country
2119 
2120     );
2121 
2122  
2123 
2124 语句描述:查询顾客和职员同在的国家。
2125 
2126  
2127 
2128 Except(与非)
2129  
2130 
2131 说明:排除相交项;延迟。即是从某集合中删除与另一个集合中相同的项。先遍历第一个集合,找出所有唯一的元素,然后再遍历第二个集合,返回第二个集合中所有未出现在前面所得元素集合中的元素。
2132 
2133  
2134 
2135 var q = (
2136 
2137      from c in db.Customers
2138 
2139      select c.Country
2140 
2141     ).Except(
2142 
2143      from e in db.Employees
2144 
2145      select e.Country
2146 
2147     );
2148 
2149  
2150 
2151 语句描述:查询顾客和职员不同的国家。
2152 
2153  
2154 
2155 LINQ to SQL语句(9)之Top/Bottom和Paging和SqlMethods
2156 Top/Bottom操作
2157  
2158 
2159 适用场景:适量的取出自己想要的数据,不是全部取出,这样性能有所加强。
2160 
2161  
2162 
2163 Take
2164  
2165 
2166 说明:获取集合的前n个元素;延迟。即只返回限定数量的结果集。
2167 
2168  
2169 
2170 var q = (
2171 
2172   from e in db.Employees
2173 
2174   orderby e.HireDate
2175 
2176   select e)
2177 
2178   .Take(5);
2179 
2180  
2181 
2182 语句描述:选择所雇用的前5个雇员。
2183 
2184  
2185 
2186 Skip
2187  
2188 
2189 说明:跳过集合的前n个元素;延迟。即我们跳过给定的数目返回后面的结果集。
2190 
2191  
2192 
2193 var q = (
2194 
2195   from p in db.Products
2196 
2197   orderby p.UnitPrice descending
2198 
2199   select p)
2200 
2201   .Skip (10);
2202 
2203  
2204 
2205 语句描述:选择10种最贵产品之外的所有产品。
2206 
2207  
2208 
2209 TakeWhile
2210  
2211 
2212 说明:直到某一条件成立就停止获取;延迟。即用其条件去依次判断源序列中的元素,返回符合判断条件的元素,该判断操作将在返回 false或源序列的末尾结束。
2213 
2214  
2215 
2216 SkipWhile
2217  
2218 
2219 说明:直到某一条件成立就停止跳过;延迟。即用其条件去判断源序列中的元素并且跳过第一个符合判断条件的元素,一旦判断返回false,接下来将不再进行判断并返回剩下的所有元素。
2220 
2221  
2222 
2223 Paging(分页)操作
2224  
2225 
2226 适用场景:结合Skip和Take就可实现对数据分页操作。
2227 
2228  
2229 
2230 1.索引
2231 var q = (
2232 
2233   from c in db.Customers
2234 
2235   orderby c.ContactName
2236 
2237   select c)
2238 
2239   .Skip(50)
2240 
2241   .Take(10);
2242 
2243  
2244 
2245 语句描述:使用Skip和Take运算符进行分页,跳过前50条记录,然后返回接下来10条记录,因此提供显示 Products表第6页的数据。
2246 
2247  
2248 
2249 2.按唯一键排序
2250 var q = (
2251 
2252    from p in db.Products
2253 
2254   where p.ProductID > 50
2255 
2256    orderby p.ProductID
2257 
2258   select p)
2259 
2260   .Take(10);
2261 
2262  
2263 
2264 语句描述:使用Where子句和Take运算符进行分页,首先筛选得到仅50 (第5页最后一个ProductID)以上的ProductID,然后按ProductID排序,最后取前10个结果,因此提供Products表第6页的数据。请注意,此方法仅适用于按唯一键排序的情况。
2265 
2266  
2267 
2268 SqlMethods操作
2269  
2270 
2271 在LINQ to SQL语句中,为我们提供了 SqlMethods操作,进一步为我们提供了方便,例如Like方法用于自定义通配表达式,Equals用于相比较是否相等。
2272 
2273  
2274 
2275 Like
2276  
2277 
2278 自定义的通配表达式。%表示零长度或任意长度的字符串;_表示一个字符;[]表示在某范围区间的一个字符;[^]表示不在某范围区间的一个字符。比如查询消费者ID以“C”开头的消费者。
2279 
2280  
2281 
2282 var q = from c in db.Customers
2283 
2284      where SqlMethods.Like(c.CustomerID, "C%")
2285 
2286      select c;
2287 
2288  
2289 
2290 比如查询消费者ID没有“AXOXT”形式的消费者:
2291 
2292  
2293 
2294 var q = from c in db.Customers
2295 
2296     where ! SqlMethods.Like(c.CustomerID, "A_O_T")
2297 
2298     select c;
2299 
2300 DateDiffDay
2301 
2302  
2303 
2304 说明:在两个变量之间比较。分别有:DateDiffDay、 DateDiffHour、DateDiffMillisecond、DateDiffMinute、DateDiffMonth、 DateDiffSecond、DateDiffYear 
2305 
2306  
2307 
2308 var q = from o in db.Orders
2309 
2310     where SqlMethods
2311 
2312     .DateDiffDay (o.OrderDate, o.ShippedDate) < 10
2313 
2314     select o;
2315 
2316  
2317 
2318 语句描述:查询在创建订单后的 10 天内已发货的所有订单。
2319 
2320  
2321 
2322 已编译查询操作(Compiled Query)
2323  
2324 
2325 说明:在之前我们没有好的方法对写出的SQL语句进行编辑重新查询,现在我们可以这样做,看下面一个例子:
2326 
2327  
2328 
2329 //1. 创建compiled query
2330 
2331 NorthwindDataContext db = newNorthwindDataContext();
2332 
2333 var fn = CompiledQuery.Compile(
2334 
2335    (NorthwindDataContext db2, string city) =>
2336 
2337   from c in db2.Customers
2338 
2339   where c.City == city
2340 
2341   select c);
2342 
2343 //2.查询城市为London的消费者,用LonCusts集合表示,这时可以用数据控件 绑定
2344 
2345 var LonCusts = fn(db, "London");
2346 
2347 //3.查询城市 为Seattle的消费者
2348 
2349 var SeaCusts = fn(db, "Seattle");
2350 
2351  
2352 
2353 语句描述:这个例子创建一个已编译查询,然后使用它检索输入城市的客户。
2354 
2355  
2356 
2357 LINQ to SQL语句(10)之Insert
2358 插入(Insert)1.简单形式
2359  
2360 
2361 说明:new一个对象,使用InsertOnSubmit方法将其加入到对应的集合中,使用SubmitChanges()提交到数据库。
2362 
2363  
2364 
2365 NorthwindDataContext db = newNorthwindDataContext();
2366 
2367 var newCustomer = new Customer
2368 
2369 {
2370 
2371   CustomerID = "MCSFT",
2372 
2373   CompanyName = "Microsoft",
2374 
2375   ContactName = "John Doe",
2376 
2377   ContactTitle = "Sales Manager",
2378 
2379   Address = "1 Microsoft Way",
2380 
2381   City = "Redmond",
2382 
2383   Region = "WA",
2384 
2385   PostalCode = "98052",
2386 
2387    Country = "USA",
2388 
2389   Phone = "(425) 555- 1234",
2390 
2391   Fax = null
2392 
2393 };
2394 
2395 db.Customers.InsertOnSubmit(newCustomer);
2396 
2397 db.SubmitChanges ();
2398 
2399  
2400 
2401 语句描述:使用InsertOnSubmit方法将新客户添加到Customers 表对象。调用SubmitChanges 将此新Customer保存到数据库。
2402 
2403  
2404 
2405 2.一对多关系
2406  
2407 
2408 说明:Category与Product是一对多的关系,提交Category(一端)的数据时,LINQ to SQL会自动将Product(多端)的数据一起提交。
2409 
2410  
2411 
2412 var newCategory = new Category
2413 
2414 {
2415 
2416   CategoryName = "Widgets",
2417 
2418   Description = "Widgets are the ……"
2419 
2420 };
2421 
2422 var newProduct = new Product
2423 
2424 {
2425 
2426   ProductName = "Blue Widget",
2427 
2428   UnitPrice = 34.56M,
2429 
2430   Category = newCategory
2431 
2432 };
2433 
2434 db.Categories.InsertOnSubmit(newCategory);
2435 
2436 db.SubmitChanges ();
2437 
2438  
2439 
2440 语句描述:使用InsertOnSubmit方法将新类别添加到Categories 表中,并将新Product对象添加到与此新Category有外键关系的Products表中。调用SubmitChanges将这些新对象及其关系保存到数据库。
2441 
2442  
2443 
2444 3.多对多关系
2445  
2446 
2447 说明:在多对多关系中,我们需要依次提交。
2448 
2449  
2450 
2451 var newEmployee = new Employee
2452 
2453 {
2454 
2455   FirstName = "Kira",
2456 
2457   LastName = "Smith"
2458 
2459 };
2460 
2461 var newTerritory = new Territory
2462 
2463 {
2464 
2465   TerritoryID = "12345",
2466 
2467   TerritoryDescription = "Anytown",
2468 
2469   Region = db.Regions.First()
2470 
2471 };
2472 
2473 var newEmployeeTerritory = newEmployeeTerritory
2474 
2475 {
2476 
2477    Employee = newEmployee,
2478 
2479   Territory = newTerritory
2480 
2481 };
2482 
2483 db.Employees.InsertOnSubmit(newEmployee);
2484 
2485 db.Territories.InsertOnSubmit(newTerritory);
2486 
2487 db.EmployeeTerritories.InsertOnSubmit(newEmployeeTerritory);
2488 
2489 db.SubmitChanges();
2490 
2491  
2492 
2493 语句描述:使用InsertOnSubmit方法将新雇员添加到Employees 表中,将新Territory添加到Territories表中,并将新 EmployeeTerritory对象添加到与此新Employee对象和新Territory对象有外键关系的EmployeeTerritories表中。调用SubmitChanges将这些新对象及其关系保持到数据库。
2494 
2495  
2496 
2497 4.使用动态CUD重写(Overrideusing Dynamic CUD)
2498  
2499 
2500 说明:CUD就是Create、Update、Delete的缩写。下面的例子就是新建一个ID(主键) 为32的Region,不考虑数据库中有没有ID为32的数据,如果有则替换原来的数据,没有则插入。
2501 
2502  
2503 
2504 Region nwRegion = new Region()
2505 
2506 {
2507 
2508   RegionID = 32,
2509 
2510   RegionDescription = "Rainy"
2511 
2512 };
2513 
2514 db.Regions.InsertOnSubmit(nwRegion);
2515 
2516 db.SubmitChanges ();
2517 
2518  
2519 
2520 语句描述:使用DataContext提供的分部方法InsertRegion插入一个区域。对SubmitChanges 的调用调用InsertRegion 重写,后者使用动态CUD运行Linq To SQL生成的默认SQL查询。
2521 
2522  
2523 
2524 LINQ to SQL语句(11)之Update
2525 更新(Update)
2526  
2527 
2528 说明:更新操作,先获取对象,进行修改操作之后,直接调用SubmitChanges()方法即可提交。注意,这里是在同一个DataContext中,对于不同的DataContex看下面的讲解。
2529 
2530  
2531 
2532 1.简单形式
2533 Customer cust =
2534 
2535   db.Customers.First(c => c.CustomerID == "ALFKI");
2536 
2537 cust.ContactTitle = "VicePresident";
2538 
2539 db.SubmitChanges();
2540 
2541  
2542 
2543 语句描述:使用 SubmitChanges将对检索到的一个Customer对象做出的更新保持回数据库。
2544 
2545  
2546 
2547 2.多项更改
2548 var q = from p in db.Products
2549 
2550      where p.CategoryID == 1
2551 
2552     select p;
2553 
2554 foreach (var p in q)
2555 
2556 {
2557 
2558   p.UnitPrice += 1.00M;
2559 
2560 }
2561 
2562 db.SubmitChanges ();
2563 
2564  
2565 
2566 语句描述:使用SubmitChanges将对检索到的进行的更新保持回数据库。
2567 
2568  
2569 
2570 LINQ to SQL语句(12)之Delete和使用Attach
2571 删除(Delete)1.简单形式
2572  
2573 
2574 说明:调用DeleteOnSubmit方法即可。
2575 
2576  
2577 
2578 OrderDetail orderDetail =
2579 
2580    db.OrderDetails.First
2581 
2582   (c => c.OrderID == 10255 && c.ProductID == 36);
2583 
2584 db.OrderDetails.DeleteOnSubmit(orderDetail);
2585 
2586 db.SubmitChanges();
2587 
2588  
2589 
2590 语句描述:使用 DeleteOnSubmit方法从OrderDetail 表中删除OrderDetail对象。调用 SubmitChanges 将此删除保持到数据库。
2591 
2592  
2593 
2594 2.一对多关系
2595  
2596 
2597 说明:Order 与OrderDetail是一对多关系,首先DeleteOnSubmit其OrderDetail(多端),其次 DeleteOnSubmit其Order(一端)。因为一端是主键。
2598 
2599  
2600 
2601 var orderDetails =
2602 
2603   from o in db.OrderDetails
2604 
2605   where o.Order.CustomerID == "WARTH" &&
2606 
2607    o.Order.EmployeeID == 3
2608 
2609   select o;
2610 
2611 var order =
2612 
2613    (from o in db.Orders
2614 
2615    where o.CustomerID == "WARTH" && o.EmployeeID ==3
2616 
2617    select o).First();
2618 
2619 foreach (OrderDetail od in orderDetails)
2620 
2621 {
2622 
2623    db.OrderDetails.DeleteOnSubmit(od);
2624 
2625 }
2626 
2627 db.Orders.DeleteOnSubmit(order);
2628 
2629 db.SubmitChanges();
2630 
2631  
2632 
2633 语句描述语句描述:使用DeleteOnSubmit方法从Order 和Order Details表中删除Order和Order Detail对象。首先从Order Details删除,然后从Orders删除。调用SubmitChanges将此删除保持到数据库。
2634 
2635  
2636 
2637 3.推理删除(Inferred Delete)
2638  
2639 
2640 说明:Order与OrderDetail是一对多关系,在上面的例子,我们全部删除CustomerID为WARTH和EmployeeID为3 的数据,那么我们不须全部删除呢?例如Order的OrderID为10248的OrderDetail有很多,但是我们只要删除 ProductID为11的OrderDetail。这时就用Remove方法。
2641 
2642  
2643 
2644 Order order = db.Orders.First(x =>x.OrderID == 10248);
2645 
2646 OrderDetail od =
2647 
2648   order.OrderDetails.First(d => d.ProductID == 11);
2649 
2650 order.OrderDetails.Remove(od);
2651 
2652 db.SubmitChanges();
2653 
2654  
2655 
2656 语句描述语句描述:这个例子说明在实体对象的引用实体将该对象从其EntitySet 中移除时,推理删除如何导致在该对象上发生实际的删除操作。仅当实体的关联映射将DeleteOnNull设置为true且CanBeNull 为false 时,才会发生推理删除行为。
2657 
2658  
2659 
2660 使用Attach更新(Updatewith Attach)
2661  
2662 
2663 说明:在对于在不同的 DataContext之间,使用Attach方法来更新数据。例如在一个名为tempdb的 NorthwindDataContext中,查询出Customer和Order,在另一个 NorthwindDataContext中,Customer的地址更新为123 First Ave,Order的 CustomerID 更新为CHOPS。
2664 
2665  
2666 
2667 //通常,通过从其他层反序列化 XML 来获取要附加的实体
2668 
2669 //不支持将实体从一个DataContext附加到另一个DataContext
2670 
2671 //因此若要复制反序列化实体的操作,将在此处重新创建这 些实体
2672 
2673 Customer c1;
2674 
2675 List<Order> deserializedOrders = newList<Order>();
2676 
2677 Customer deserializedC1;
2678 
2679 using (NorthwindDataContext tempdb = newNorthwindDataContext())
2680 
2681 {
2682 
2683   c1 = tempdb.Customers.Single(c => c.CustomerID =="ALFKI");
2684 
2685   deserializedC1 = new Customer
2686 
2687    {
2688 
2689     Address = c1.Address,
2690 
2691     City = c1.City,
2692 
2693     CompanyName = c1.CompanyName,
2694 
2695     ContactName = c1.ContactName,
2696 
2697     ContactTitle = c1.ContactTitle,
2698 
2699     Country = c1.Country,
2700 
2701     CustomerID = c1.CustomerID,
2702 
2703     Fax = c1.Fax,
2704 
2705     Phone = c1.Phone,
2706 
2707      PostalCode = c1.PostalCode,
2708 
2709     Region = c1.Region
2710 
2711   };
2712 
2713   Customer tempcust =
2714 
2715      tempdb.Customers.Single(c => c.CustomerID == "ANTON");
2716 
2717   foreach (Order o in tempcust.Orders)
2718 
2719   {
2720 
2721      deserializedOrders.Add(new Order
2722 
2723     {
2724 
2725        CustomerID = o.CustomerID,
2726 
2727       EmployeeID = o.EmployeeID,
2728 
2729       Freight = o.Freight,
2730 
2731        OrderDate = o.OrderDate,
2732 
2733       OrderID = o.OrderID,
2734 
2735       RequiredDate = o.RequiredDate,
2736 
2737       ShipAddress = o.ShipAddress,
2738 
2739       ShipCity = o.ShipCity,
2740 
2741       ShipName = o.ShipName,
2742 
2743       ShipCountry = o.ShipCountry,
2744 
2745       ShippedDate = o.ShippedDate,
2746 
2747       ShipPostalCode = o.ShipPostalCode,
2748 
2749       ShipRegion = o.ShipRegion,
2750 
2751       ShipVia = o.ShipVia
2752 
2753     });
2754 
2755   }
2756 
2757 }
2758 
2759 using (NorthwindDataContext db2 = newNorthwindDataContext())
2760 
2761 {
2762 
2763   //将第一个实体附加到当前数据上下文,以跟踪更改
2764 
2765   //对Customer更新,不能写错
2766 
2767    db2.Customers.Attach(deserializedC1);
2768 
2769   //更改所跟踪的实体
2770 
2771   deserializedC1.Address = "123 First Ave";
2772 
2773   // 附加订单列表中的所有实体
2774 
2775   db2.Orders.AttachAll (deserializedOrders);
2776 
2777   //将订单更新为属于其他客户
2778 
2779    foreach (Order o in deserializedOrders)
2780 
2781   {
2782 
2783      o.CustomerID = "CHOPS";
2784 
2785   }
2786 
2787   //在当前数据上下文中提交更改
2788 
2789   db2.SubmitChanges();
2790 
2791 }
2792 
2793  
2794 
2795 语句描述:从另一个层中获取实体,使用Attach和AttachAll将反序列化后的实体附加到数据上下文,然后更新实体。更改被提交到数据库。
2796 
2797  
2798 
2799 使用Attach更新和删除(Update and Delete with Attach)
2800 
2801  
2802 
2803 说明:在不同的DataContext中,实现插入、更新、删除。看下面的一个例子:
2804 
2805  
2806 
2807 //通常,通过从其他层 反序列化XML获取要附加的实体
2808 
2809 //此示例使用 LoadWith 在一个查询中预 先加载客户和订单,
2810 
2811 //并禁用延迟加载
2812 
2813 Customer cust = null;
2814 
2815 using (NorthwindDataContext tempdb = newNorthwindDataContext())
2816 
2817 {
2818 
2819   DataLoadOptions shape = new DataLoadOptions();
2820 
2821    shape.LoadWith<Customer>(c => c.Orders);
2822 
2823   //加载第一个客户实体及其订单
2824 
2825   tempdb.LoadOptions = shape;
2826 
2827    tempdb.DeferredLoadingEnabled = false;
2828 
2829   cust = tempdb.Customers.First(x => x.CustomerID =="ALFKI");
2830 
2831 }
2832 
2833 Order orderA = cust.Orders.First();
2834 
2835 Order orderB = cust.Orders.First(x =>x.OrderID > orderA.OrderID);
2836 
2837 using (NorthwindDataContext db2 = newNorthwindDataContext())
2838 
2839 {
2840 
2841   //将第一个实体附加到当前数据上下文,以跟踪更改
2842 
2843    db2.Customers.Attach(cust);
2844 
2845   //附加相关订单以进行跟踪; 否则将在提交时插入它们
2846 
2847   db2.Orders.AttachAll(cust.Orders.ToList ());
2848 
2849   //更新客户的Phone.
2850 
2851   cust.Phone = "2345 5436";
2852 
2853   //更新第一个订单OrderA的ShipCity.
2854 
2855    orderA.ShipCity = "Redmond";
2856 
2857   //移除第二个订单 OrderB.
2858 
2859   cust.Orders.Remove(orderB);
2860 
2861   //添加一个新的订单Order到客户Customer中.
2862 
2863   Order orderC = new Order() { ShipCity = "New York" };
2864 
2865   cust.Orders.Add (orderC);
2866 
2867   //提交执行
2868 
2869   db2.SubmitChanges();
2870 
2871 }
2872 
2873  
2874 
2875 语句描述:从一个上下文提取实体,并使用 Attach 和 AttachAll 附加来自其他上下文的实体,然后更新这两个实体,删除一个实体,添加另一个实体。更改被提交到数据库。
2876 
2877  
2878 
2879 LINQ to SQL语句(13)之开放式并发控制和事务
2880 Simultaneous Changes开放式并发控制
2881  
2882 
2883 下表介绍 LINQ to SQL 文档中涉及开放式并发的术语:
2884 
2885  
2886 
2887 术语说明
2888 
2889 并发两个或更多用户同时尝试更新同一数据库行的情形。
2890 
2891 并发冲突两个或更多用户同时尝试向一行的一列或多列提交冲突值的情形。
2892 
2893 并发控制用于解决并发冲突的技术。
2894 
2895 开放式并发控制先调查其他事务是否已更改了行中的值,再允许提交更改的技术。相比之下,保守式并发控制则是通过锁定记录来避免发生并发冲突。之所以称作开放式控制,是因为它将一个事务干扰另一事务视为不太可能发生。
2896 
2897 冲突解决通过重新查询数据库刷新出现冲突的项,然后协调差异的过程。刷新对象时,LINQ to SQL 更改跟踪器会保留以下数据:最初从数据库获取并用于更新检查的值通过后续查询获得的新数据库值。 LINQ to SQL 随后会确定相应对象是否发生冲突(即它的一个或多个成员值是否已发生更改)。如果此对象发生冲突,LINQ to SQL 下一步会确定它的哪些成员发生冲突。LINQ to SQL 发现的任何成员冲突都会添加到冲突列表中。
2898 
2899  
2900 
2901  
2902 
2903 在 LINQ to SQL 对象模型中,当以下两个条件都得到满足时,就会发生“开放式并发冲突”:客户端尝试向数据库提交更改;数据库中的一个或多个更新检查值自客户端上次读取它们以来已得到更新。此冲突的解决过程包括查明对象的哪些成员发生冲突,然后决定您希望如何进行处理。
2904 
2905  
2906 
2907 开放式并发(Optimistic Concurrency)
2908  
2909 
2910 说明:这个例子中在你读取数据之前,另外一个用户已经修改并提交更新了这个数据,所以不会出现冲突。
2911 
2912  
2913 
2914 //我们打开一个新的连接来模拟另外一个用户
2915 
2916 NorthwindDataContext otherUser_db = newNorthwindDataContext();
2917 
2918 var otherUser_product =
2919 
2920   otherUser_db.Products.First(p => p.ProductID == 1);
2921 
2922 otherUser_product.UnitPrice = 999.99M;
2923 
2924 otherUser_db.SubmitChanges();
2925 
2926 //我们当前连接
2927 
2928 var product = db.Products.First(p =>p.ProductID == 1);
2929 
2930 product.UnitPrice = 777.77M;
2931 
2932 try
2933 
2934 {
2935 
2936   db.SubmitChanges();//当前连接执行成功
2937 
2938 }
2939 
2940 catch (ChangeConflictException)
2941 
2942 {
2943 
2944 }
2945 
2946  
2947 
2948 说明:我们读取数据之后,另外一个用户获取并提交更新了这个数据,这时,我们更新这个数据时,引起了一个并发冲突。系统发生回滚,允许你可以从数据库检索新更新的数据,并决定如何继续进行您自己的更新。
2949 
2950  
2951 
2952 //当前 用户
2953 
2954 var product = db.Products.First(p =>p.ProductID == 1);
2955 
2956 //我们打开一个新的连接来模拟另外一个用户
2957 
2958 NorthwindDataContext otherUser_db = newNorthwindDataContext() ;
2959 
2960 var otherUser_product =
2961 
2962   otherUser_db.Products.First(p => p.ProductID == 1);
2963 
2964 otherUser_product.UnitPrice = 999.99M;
2965 
2966 otherUser_db.SubmitChanges();
2967 
2968 //当前用户修改
2969 
2970 product.UnitPrice = 777.77M;
2971 
2972 try
2973 
2974 {
2975 
2976    db.SubmitChanges();
2977 
2978 }
2979 
2980 catch (ChangeConflictException)
2981 
2982 {
2983 
2984   //发生异常!
2985 
2986 }
2987 
2988  
2989 
2990 Transactions事务
2991 
2992  
2993 
2994 LINQto SQL 支持三种事务模型,分别是:
2995 
2996  
2997 
2998 显式本地事务:调用 SubmitChanges 时,如果 Transaction 属性设置为事务,则在同一事务的上下文中执行 SubmitChanges 调用。成功执行事务后,要由您来提交或回滚事务。与事务对应的连接必须与用于构造 DataContext 的连接匹配。如果使用其他连接,则会引发异常。
2999 
3000  
3001 
3002 显式可分发事务:可以在当前 Transaction 的作用域中调用 LINQ to SQL API(包括但不限于 SubmitChanges)。LINQ to SQL 检测到调用是在事务的作用域内,因而不会创建新的事务。在这种情况下, <token>vbtecdlinq</token> 还会避免关闭连接。您可以在此类事 务的上下文中执行查询和SubmitChanges 操作。
3003 
3004  
3005 
3006 隐式事务:当您调用 SubmitChanges 时,LINQ to SQL 会检查此调用是否在 Transaction 的作用域内或者 Transaction 属性是否设置为由用户启动的本地事务。如果这两个事务它均未找到,则 LINQ to SQL 启动本地事务,并使用此事务执行所生成的 SQL 命令。当所有 SQL 命令均已成功执行完毕时,LINQ to SQL 提交本地事务并返回。
3007 
3008  
3009 
3010 1.Implicit(隐式)
3011  
3012 
3013 说明:这个例子在执行SubmitChanges ()操作时,隐式地使用了事务。因为在更新2种产品的库存数量时,第二个产品库存数量为负数了,违反了服务器上的 CHECK 约束。这导致了更新产品全部失败了,系统回滚到这个操作的初始状态。
3014 
3015 try
3016 
3017 {
3018 
3019   Product prod1 = db.Products.First(p => p.ProductID == 4);
3020 
3021   Product prod2 = db.Products.First(p => p.ProductID == 5);
3022 
3023    prod1.UnitsInStock -= 3;
3024 
3025   prod2.UnitsInStock -= 5;//错误:库存 数量的单位不能是负数
3026 
3027   //要么全部成功要么全部失败
3028 
3029    db.SubmitChanges();
3030 
3031 }
3032 
3033 catch (System.Data.SqlClient.SqlExceptione)
3034 
3035 {
3036 
3037   //执行异常处理
3038 
3039 }
3040 
3041  
3042 
3043 2.Explicit(显式)
3044  
3045 
3046 说明:这个例子使用显式事务。通过在事务中加入对数据的读取以防止出现开放式并发异常,显式事务可以提供更多的保护。如同上一个查询中,更新 prod2 的 UnitsInStock 字段将使该字段为负值,而这违反了数据库中的 CHECK 约束。这导致更新这两个产品的事务失败,此时将回滚所有更改。
3047 
3048  
3049 
3050 using (TransactionScope ts = new TransactionScope())
3051 
3052 {
3053 
3054   try
3055 
3056   {
3057 
3058      Product prod1 = db.Products.First(p => p.ProductID == 4);
3059 
3060     Product prod2 = db.Products.First(p => p.ProductID == 5);
3061 
3062     prod1.UnitsInStock -= 3;
3063 
3064     prod2.UnitsInStock -= 5;//错误:库存数量的单位不能是负数
3065 
3066     db.SubmitChanges();
3067 
3068   }
3069 
3070   catch (System.Data.SqlClient.SqlException e)
3071 
3072   {
3073 
3074     //执行异常处理
3075 
3076   }
3077 
3078 }
3079 
3080  
3081 
3082 LINQ to SQL语句(14)之Null语义和DateTime
3083 Null语义
3084  
3085 
3086 说明:下面第一个例子说明查询ReportsToEmployee为null的雇员。第二个例子使用Nullable<T>.HasValue查询雇员,其结果与第一个例 子相同。在第三个例子中,使用Nullable<T>.Value来返回ReportsToEmployee不为null的雇员的ReportsTo的值。
3087 
3088  
3089 
3090 1.Null
3091  
3092 
3093 查找不隶属于另一个雇员的所有雇员:
3094 
3095  
3096 
3097 var q =
3098 
3099   from e in db.Employees
3100 
3101   where e.ReportsToEmployee == null
3102 
3103    select e;
3104 
3105 2.Nullable<T>.HasValue
3106  
3107 
3108 查找不隶属于另一个雇员的所有雇员:
3109 
3110  
3111 
3112 var q =
3113 
3114   from e in db.Employees
3115 
3116   where !e.ReportsTo.HasValue
3117 
3118   select e;
3119 
3120 3.Nullable<T>.Value
3121 
3122  
3123 
3124 返回前者的EmployeeID 编号。请注意 .Value 为可选:
3125 
3126  
3127 
3128 var q =
3129 
3130   from e in db.Employees
3131 
3132   where e.ReportsTo.HasValue
3133 
3134   select new
3135 
3136   {
3137 
3138     e.FirstName,
3139 
3140     e.LastName,
3141 
3142     ReportsTo = e.ReportsTo.Value
3143 
3144   };
3145 
3146 日期函数
3147  
3148 
3149 LINQ to SQL支持以下 DateTime方法。但是,SQLServer和CLR的DateTime类型在范围和计时周期精度上不同,如下表。
3150 
3151  
3152 
3153 类型最小值 最大 值 计时周期
3154 
3155 System.DateTime 00011199991231100 毫微秒(0.0000001秒)
3156 
3157 T-SQL DateTime 175311999912313.33… 毫秒(0.0033333 秒)
3158 
3159 T-SQL SmallDateTime 1900112079661 分钟(60 秒)
3160 
3161  
3162 
3163  
3164 
3165 CLR DateTime 类型与SQL Server类型相比,前者范围更 大、精度更高。因此来自SQLServer的数据用CLR类型表示时,绝不会损失量值或精度。但如果反过来的话,则范围可能会减小,精度可能会降低;SQL Server 日期不存在TimeZone概念,而在CLR中支持这个功能。
3166 
3167  
3168 
3169 我们在LINQ to SQL查询使用以当地时间、UTC 或固定时间要自己执行转换。
3170 
3171  
3172 
3173 下面用三个实例说明一下。
3174 
3175  
3176 
3177 1.DateTime.Year
3178 var q =
3179 
3180   from o in db.Orders
3181 
3182   where o.OrderDate.Value.Year == 1997
3183 
3184    select o;
3185 
3186  
3187 
3188 语句描述:这个例子使用DateTime 的Year 属性查找1997 年下的订单。
3189 
3190  
3191 
3192 2.DateTime.Month
3193 var q =
3194 
3195   from o in db.Orders
3196 
3197   where o.OrderDate.Value.Month == 12
3198 
3199   select o;
3200 
3201  
3202 
3203 语句描述:这个例子使用DateTime的Month属性查找十二月下的订单。
3204 
3205  
3206 
3207 3.DateTime.Day
3208 var q =
3209 
3210   from o in db.Orders
3211 
3212   where o.OrderDate.Value.Day == 31
3213 
3214   select o;
3215 
3216  
3217 
3218 语句描述:这个例子使用DateTime的Day属性查找某月 31 日下的订单。
3219 
3220  
3221 
3222  
3223 
3224 LINQ to SQL语句(15)之String
3225 字符串(String)
3226  
3227 
3228 LINQ to SQL支持以下String方法。但是不同的是默认 情况下System.String方法区分大小写。而SQL则不区分大小写。
3229 
3230  
3231 
3232 1.字符串串联(StringConcatenation)
3233 var q =
3234 
3235   from c in db.Customers
3236 
3237   select new
3238 
3239   {
3240 
3241      c.CustomerID,
3242 
3243     Location = c.City + ", " + c.Country
3244 
3245   };
3246 
3247  
3248 
3249 语句描述:这个例子使用+运算符在形成经计算得出的客户Location值过程中将字符串字段和字符串串联在一起。
3250 
3251  
3252 
3253 2.String.Length
3254 var q =
3255 
3256   from p in db.Products
3257 
3258   where p.ProductName.Length < 10
3259 
3260   select p;
3261 
3262  
3263 
3264 语句描述:这个例子使用Length属性查找名称短于10个字符的所有产品。
3265 
3266  
3267 
3268 3.String.Contains(substring)
3269 var q =
3270 
3271   from c in db.Customers
3272 
3273   where c.ContactName.Contains ("Anders")
3274 
3275   select c;
3276 
3277  
3278 
3279 语句描述:这个例子使用Contains方法查找所有其联系人姓名中包含“Anders”的客户。
3280 
3281  
3282 
3283 4.String.IndexOf(substring)
3284 var q =
3285 
3286   from c in db.Customers
3287 
3288   select new
3289 
3290   {
3291 
3292      c.ContactName,
3293 
3294     SpacePos = c.ContactName.IndexOf(" ")
3295 
3296   };
3297 
3298  
3299 
3300 语句描述:这个例子使用IndexOf方法查找每个客户联系人姓名中出现第一个空格的位置。
3301 
3302  
3303 
3304 5.String.StartsWith (prefix)
3305 var q =
3306 
3307   from c in db.Customers
3308 
3309   where c.ContactName.StartsWith("Maria")
3310 
3311   select c;
3312 
3313  
3314 
3315 语句描述:这个例子使用StartsWith方法查找联系人姓名以“Maria”开头的客户。
3316 
3317  
3318 
3319 6.String.EndsWith(suffix)
3320 var q =
3321 
3322   from c in db.Customers
3323 
3324   where c.ContactName.EndsWith("Anders")
3325 
3326   select c;
3327 
3328  
3329 
3330 语句描述:这个例子使用EndsWith方法查找联系人姓名以“Anders”结尾的客户。
3331 
3332  
3333 
3334 7.String.Substring(start)
3335 var q =
3336 
3337   from p in db.Products
3338 
3339   select p.ProductName.Substring(3);
3340 
3341  
3342 
3343 语句描述:这个例子使用Substring方法返回产品名称中从第四个字母开始的部分。
3344 
3345  
3346 
3347 8.String.Substring (start, length)
3348 var q =
3349 
3350   from e in db.Employees
3351 
3352    where e.HomePhone.Substring(6, 3) == "555"
3353 
3354   select e;
3355 
3356  
3357 
3358 语句描述:这个例子使用Substring方法查找家庭电话号码第七位到第九位是“555”的雇员。
3359 
3360  
3361 
3362 9.String.ToUpper()
3363 var q =
3364 
3365   from e in db.Employees
3366 
3367   select new
3368 
3369   {
3370 
3371     LastName = e.LastName.ToUpper(),
3372 
3373     e.FirstName
3374 
3375   };
3376 
3377  
3378 
3379 语句描述:这个例子使用ToUpper方法返回姓氏已转换为大写的雇员姓名。
3380 
3381  
3382 
3383 10.String.ToLower()
3384 var q =
3385 
3386   from c in db.Categories
3387 
3388   select c.CategoryName.ToLower();
3389 
3390  
3391 
3392 语句描述:这个例子使用ToLower方法返回已转换为小写的类别名称。
3393 
3394  
3395 
3396 11.String.Trim()
3397 var q =
3398 
3399   from e in db.Employees
3400 
3401   select e.HomePhone.Substring(0, 5).Trim ();
3402 
3403  
3404 
3405 语句描述:这个例子使用Trim方法返回雇员家庭电话号码的前五位,并移除前导和尾随空格。
3406 
3407  
3408 
3409 12.String.Insert(pos, str)
3410 var q =
3411 
3412   from e in db.Employees
3413 
3414   where e.HomePhone.Substring(4, 1) == ")"
3415 
3416   select e.HomePhone.Insert(5, ":");
3417 
3418  
3419 
3420 语句描述:这个例子使用 Insert方法返回第五位为 ) 的雇员电话号码的序列,并在 ) 后面插入一个 :。
3421 
3422  
3423 
3424 13.String.Remove(start)
3425 var q =
3426 
3427   from e in db.Employees
3428 
3429   where e.HomePhone.Substring(4, 1) == ") "
3430 
3431   select e.HomePhone.Remove(9);
3432 
3433  
3434 
3435 语句描述:这个例子使用Remove方法返回第五位为 ) 的雇员电话号码的序列,并移除从第十个字符开始的所有字符。
3436 
3437  
3438 
3439 14.String.Remove(start, length)
3440 var q =
3441 
3442   from e in db.Employees
3443 
3444   where e.HomePhone.Substring(4, 1) == ")"
3445 
3446   select e.HomePhone.Remove(0, 6);
3447 
3448  
3449 
3450 语句描述:这个例子使用Remove方法返回第五位为 ) 的雇员电话号码的序列,并移除前六个字符。
3451 
3452  
3453 
3454 15.String.Replace(find, replace)
3455 var q =
3456 
3457   from s in db.Suppliers
3458 
3459   select new
3460 
3461   {
3462 
3463      s.CompanyName,
3464 
3465     Country = s.Country
3466 
3467     .Replace ("UK", "United Kingdom")
3468 
3469     .Replace ("USA", "United States of America")
3470 
3471   };
3472 
3473  
3474 
3475 语句描述:这个例子使用 Replace 方法返回 Country 字段中UK 被替换为 United Kingdom 以及USA 被替换为 United States of America 的供 应商信息。
3476 
3477  
3478 
3479  
3480 
3481 LINQ to SQL语句(16)之对象标识
3482 对象标识
3483  
3484 
3485 运行库中的对象具有唯一标识。引用同一对象的两个变量实际上是引用此对象的同一实例。你更改一个变量后,可以通过另一个变量看到这些更改。
3486 
3487  
3488 
3489 关系数据库表中的行不具有唯一标识。由于每一行都具有唯一的主键,因此任何两行都不会共用同一键值。
3490 
3491  
3492 
3493 实际上,通常我们是将数据从数据库中提取出来放入另一层中,应用程序在该层对数据进行处理。这就是 LINQ to SQL 支持的模型。将数据作为行从数据库中提取出来时,你不期望表示相同数据的两行实际上对应于相同的行实例。如果您查询特定客户两次,您将获得两行数据。每一行包含相同的信息。
3494 
3495  
3496 
3497 对于对象。你期望在你反复向 DataContext 索取相同的信息时,它实际上会为你提供同一对象实例。你将它们设计为层次结构或关系图。你希望像检索实物一样检索它们,而不希望仅仅因为你多次索要同一内容而收到大量的复制实例。
3498 
3499  
3500 
3501 在 LINQ to SQL 中, DataContext 管理对象标识。只要你从数据库中检索新行,该行就会由其主键记录到标识表中,并且会创建一个新的对象。只要您检索该行,就会将原始对象实例传递回应用程序。通过这种方式,DataContext 将数据库看到的标识(即主键)的概念转换成相应语言看到的标识(即实例)的概念。应用程序只看到处于第一次检索时的状态的对象。新数据如果不同,则会被丢弃。
3502 
3503  
3504 
3505 LINQ to SQL 使用此方法来管理本地对象的完整性,以支持开放式更新。由于在最初创建对象 后唯一发生的更改是由应用程序做出的,因此应用程序的意向是很明确的。如果在中间阶段外部某一方做了更改,则在调用 SubmitChanges() 时会识别出这些更改。
3506 
3507  
3508 
3509 以上来自MSDN,的确,看了有点“正规”,下面我用两个例子说明一下。
3510 
3511  
3512 
3513 对象缓存
3514  
3515 
3516 在第一个示例中,如果我们执行同一查询两次,则每次都会收到对内存中同一对象的引用。很明显,cust1和cust2是同一个对象引用。
3517 
3518  
3519 
3520 Customer cust1 = db.Customers.First(c =>c.CustomerID == "BONAP");
3521 
3522 Customer cust2 = db.Customers.First(c =>c.CustomerID == "BONAP");
3523 
3524  
3525 
3526 下面的示例中,如果您执行返回数据库中同一行的不同查询,则您每次都会收到对内存中同一对象的引用。cust1和cust2是同一个对象引用,但是数据库查询了两次。
3527 
3528  
3529 
3530 Customer cust1 = db.Customers.First(c =>c.CustomerID == "BONAP");
3531 
3532 Customer cust2 = (
3533 
3534   from o in db.Orders
3535 
3536   where o.Customer.CustomerID == "BONAP"
3537 
3538   select o )
3539 
3540   .First()
3541 
3542   .Customer;
3543 
3544  
3545 
3546 LINQ to SQL语句(17)之对象加载
3547 对象加载延迟加载
3548  
3549 
3550 在查询某对象时,实际上你只查询该对象。不会同时自动获取这个对象。这就是延迟加载。
3551 
3552  
3553 
3554 例如,您可能需要查看客户数据和订单数据。你最初不一定需要检索与每个客户有关的所有订单数据。其优点是你可以使用延迟加载将额外信息的检索操作延迟到你确实需要检索它们时再进行。请看下面的示例:检索出来CustomerID,就根据这个ID查询出OrderID。
3555 
3556  
3557 
3558 var custs =
3559 
3560    from c in db.Customers
3561 
3562    where c.City == "Sao Paulo"
3563 
3564    select c;
3565 
3566 //上面 的查询句法不会导致语句立即执行,仅仅是一个描述性的语句,
3567 
3568 只有需要的时候才会执行它
3569 
3570 foreach (var cust in custs)
3571 
3572 {
3573 
3574    foreach (var ord in cust.Orders)
3575 
3576   {
3577 
3578     //同时查看客户数据和订单数据
3579 
3580   }
3581 
3582 }
3583 
3584  
3585 
3586 语句描述:原始查询未请求数据,在所检索到各个对象的链接中导航如何能导致触发对数据库的新查询。
3587 
3588  
3589 
3590 预先加载:LoadWith 方法
3591  
3592 
3593 你如果想要同时查询出一些对象的集合的方法。LINQ to SQL 提供了 DataLoadOptions用于立即加载对象。方法包括:
3594 
3595  
3596 
3597 LoadWith 方法,用于立即加载与主目标相关的数据。
3598 
3599  
3600 
3601 AssociateWith 方法,用于筛选为特定关系检索到的对象。
3602 
3603  
3604 
3605 使用 LoadWith方法指定应同时检索与主目标相关的哪些数据。例如,如果你知道你需要有关客户的订单的信息,则可以使用 LoadWith 来确保在检索客户信息的同时检索订单信息。使用此方法可仅访问一次数据库,但同时获取两组信息。
3606 
3607  
3608 
3609 在下面的示例中,我们通过设置DataLoadOptions,来指示DataContext 在加载Customers的同时把对应的Orders一起加载,在执行查询时会检索位于Sao Paulo的所有 Customers 的所有 Orders。这样一来,连续访问 Customer 对象的 Orders 属性不会触发新的数据库查询。在执行时生成的SQL语句使用了左连接。
3610 
3611  
3612 
3613 NorthwindDataContext db = newNorthwindDataContext ();
3614 
3615 DataLoadOptions ds = new DataLoadOptions();
3616 
3617 ds.LoadWith<Customer>(p =>p.Orders);
3618 
3619 db.LoadOptions = ds;
3620 
3621 var custs = (
3622 
3623    from c in db2.Customers
3624 
3625    where c.City == "Sao Paulo"
3626 
3627    select c);
3628 
3629 foreach (var cust in custs)
3630 
3631 {
3632 
3633   foreach (var ord in cust.Orders)
3634 
3635   {
3636 
3637     Console.WriteLine ("CustomerID {0} has an OrderID {1}.",
3638 
3639        cust.CustomerID,
3640 
3641       ord.OrderID);
3642 
3643   }
3644 
3645 }
3646 
3647  
3648 
3649 语句描述:在原始查询过程中使用 LoadWith 请求相关数据,以便稍后在检索到的各个对象中导航时不需要对数据库进行额外的往返。
3650 
3651  
3652 
3653 LINQ to SQL语句(18)之运算符转换
3654 运算符转换
3655 
3656 1.AsEnumerable:将类型转换为泛型 IEnumerable
3657  
3658 
3659 使用 AsEnumerable<TSource> 可返回类型化为泛型 IEnumerable的参数。在 此示例中,LINQ toSQL(使用默认泛型 Query)会尝试将查询转换为 SQL 并在服务器上执行。但 where 子句引用用户定义的客户端方法 (isValidProduct),此方法无法转换为 SQL。
3660 
3661  
3662 
3663 解决方法是指定 where 的客户端泛型 IEnumerable<T> 实现以替换泛型 IQueryable<T>。可通过调用 AsEnumerable<TSource>运算符来执行此操作。
3664 
3665  
3666 
3667 var q =
3668 
3669   from p in db.Products.AsEnumerable()
3670 
3671   where isValidProduct(p)
3672 
3673   select p;
3674 
3675  
3676 
3677 语句描述:这个例子就是使用AsEnumerable以便使用Where的客户端IEnumerable实现,而不是默认的 IQueryable将在服务器上转换为SQL并执行的默认Query<T>实现。这很有必要,因为Where子句引用了用户定义的客户端方法isValidProduct,该方法不能转换为SQL。
3678 
3679  
3680 
3681 2.ToArray:将序列转换为数组
3682  
3683 
3684 使用 ToArray <TSource>可从序列创建数组。
3685 
3686  
3687 
3688 var q =
3689 
3690   from c in db.Customers
3691 
3692   where c.City == "London"
3693 
3694    select c;
3695 
3696 Customer[] qArray = q.ToArray();
3697 
3698  
3699 
3700 语句描述:这个例子使用 ToArray 将查询直接计算为数组。
3701 
3702  
3703 
3704 3.ToList:将序列转换为泛型列表
3705  
3706 
3707 使用 ToList<TSource>可从序列创建泛型列表。下面的示例使用 ToList<TSource>直接将查询的计算结果放入泛型 List<T>3708 
3709  
3710 
3711 var q =
3712 
3713   from e in db.Employees
3714 
3715   where e.HireDate >= new DateTime(1994, 1, 1)
3716 
3717   select e;
3718 
3719 List<Employee> qList = q.ToList();
3720 
3721 4.ToDictionary:将序列转化为字典
3722  
3723 
3724 使用Enumerable.ToDictionary<TSource, TKey>方法可 以将序列转化为字典。TSource表示source中的元素的类型;TKey表示keySelector返回的键的类型。其返回一个包含键和值的Dictionary<TKey, TValue>3725 
3726  
3727 
3728 var q =
3729 
3730   from p in db.Products
3731 
3732   where p.UnitsInStock <= p.ReorderLevel && ! p.Discontinued
3733 
3734   select p;
3735 
3736 Dictionary<int, Product> qDictionary=
3737 
3738   q.ToDictionary(p => p.ProductID);
3739 
3740 foreach (int key in qDictionary.Keys)
3741 
3742 {
3743 
3744    Console.WriteLine(key);
3745 
3746 }
3747 
3748  
3749 
3750 语句描述:这个例子使用 ToDictionary 将查询和键表达式直接键表达式直接计算为 Dictionary<K, T>3751 
3752  
3753 
3754 LINQ to SQL语句(19)之ADO.NET与LINQ to SQL
3755 ADO.NET与LINQ to SQL
3756 
3757  
3758 
3759 它基于由 ADO.NET 提供程序模型提供的服务。因此,我们可以将 LINQ to SQL 代码与现有的 ADO.NET 应用程序混合在一起,将当前 ADO.NET 解决方案迁移到 LINQ to SQL。
3760 
3761  
3762 
3763 1.连接
3764  
3765 
3766 在创建 LINQ to SQL DataContext 时,可以提供现有 ADO.NET 连接。对DataContext 的所有操作(包括查询)都使用所提供的这个连接。如果此连接已经打开,则在您使用完此连接时,LINQ to SQL 会保持它的打开状态不变。我们始终可以访问此连接,另外还可以使用 Connection 属性自行关闭它。
3767 
3768  
3769 
3770 //新建一个 标准的ADO.NET连接:
3771 
3772 SqlConnection nwindConn = new SqlConnection(connString);
3773 
3774 nwindConn.Open();
3775 
3776 // ... 其它的ADO.NET数据操作 代码... //
3777 
3778 //利用现有的ADO.NET连接来创建一个DataContext:
3779 
3780 Northwind interop_db = new Northwind(nwindConn);
3781 
3782 var orders =
3783 
3784    from o in interop_db.Orders
3785 
3786    where o.Freight > 500.00M
3787 
3788    select o;
3789 
3790 //返回Freight>500.00M的订单
3791 
3792 nwindConn.Close();
3793 
3794  
3795 
3796 语句描述:这个例子使用预先存在的ADO.NET 连接创建Northwind对象,本例中的查询返回运费至少为500.00 的所有订单。
3797 
3798  
3799 
3800 2.事务
3801  
3802 
3803 当我们已经启动了自己的数据库事务并且我们希望 DataContext 包含在内时,我们可以向 DataContext 提供此事务。
3804 
3805  
3806 
3807 通过 .NET Framework 创建事务的首选方法是使用 TransactionScope 对象。通过使用此方法,我们可以创建跨数据库及其他驻留在内存中的资源管理器执行的分布式事务。事务范围几乎不需要资源就可以启动。它们仅在事务范围内存在多个连接时才将自身提升为分布式事务。
3808 
3809  
3810 
3811 using (TransactionScope ts = newTransactionScope())
3812 
3813 {
3814 
3815   db.SubmitChanges();
3816 
3817   ts.Complete();
3818 
3819 }
3820 
3821  
3822 
3823 注意:不能将此方法用于所有数据库。例如,SqlClient 连接在针对 SQL Server 2000 服务器使用时无法提升系统事务。它采取的方法是,只要它发现有使用事务范围的情况,它就会自动向完整的分布式事务登记。
3824 
3825  
3826 
3827 下面用一个例子说明一下事务的使用方法。在这里,也说明了重用 ADO.NET 命令和 DataContext 之间的同一连接。
3828 
3829  
3830 
3831 var q =
3832 
3833    from p in db.Products
3834 
3835    where p.ProductID == 3
3836 
3837    select p;
3838 
3839 //使用LINQ to SQL查询出来
3840 
3841 //新建一个标准的ADO.NET连接:
3842 
3843 SqlConnection nwindConn = newSqlConnection(connString);
3844 
3845 nwindConn.Open();
3846 
3847 //利用现有的 ADO.NET连接来创建一个DataContext:
3848 
3849 Northwind interop_db = newNorthwind(nwindConn);
3850 
3851 SqlTransaction nwindTxn =nwindConn.BeginTransaction();
3852 
3853 try
3854 
3855 {
3856 
3857   SqlCommand cmd = new SqlCommand("UPDATE Products SET"
3858 
3859    +"QuantityPerUnit = 'single item' WHERE ProductID = 3");
3860 
3861   cmd.Connection = nwindConn;
3862 
3863    cmd.Transaction = nwindTxn;
3864 
3865   cmd.ExecuteNonQuery();
3866 
3867    interop_db.Transaction = nwindTxn;
3868 
3869   Product prod1 = interop_db.Products.First(p => p.ProductID == 4);
3870 
3871   Product prod2 = interop_db.Products.First(p => p.ProductID == 5);
3872 
3873    prod1.UnitsInStock -= 3;
3874 
3875   prod2.UnitsInStock -= 5;//这有一个错 误,不能为负数
3876 
3877   interop_db.SubmitChanges();
3878 
3879    nwindTxn.Commit();
3880 
3881 }
3882 
3883 catch (Exception e)
3884 
3885 {
3886 
3887   // 如果有一个错误,所有的操作回滚
3888 
3889   Console.WriteLine (e.Message);
3890 
3891 }
3892 
3893 nwindConn.Close();
3894 
3895  
3896 
3897 语句描述:这个例子使用预先存在的 ADO.NET 连接创建 Northwind 对象,然后与此对象共享一个 ADO.NET 事务。此事务既用于通过 ADO.NET 连接执行 SQL 命令,又用于通过 Northwind 对象提交更改。当事务因违反 CHECK 约束而中止时,将回滚所有更改,包括通过 SqlCommand 做出的更改,以及通过Northwind 对象做出的更改。
3898 
3899  
3900 
3901  
3902 
3903 LINQ to SQL语句(20)之存储过程
3904 存储过程
3905 
3906  
3907 
3908 在我们编写程序中,往往需要一些存储过程,在LINQ to SQL中怎么使用呢?也许比原来的更简单些。下面我们以NORTHWND.MDF数据库中自带的几个存储过程来理解一下。
3909 
3910  
3911 
3912 1.标量返回
3913  
3914 
3915 在数据库中,有名为 Customers Count By Region的存储过程。该存储过程返回顾客所在"WA"区域的数量。
3916 
3917  
3918 
3919 ALTER PROCEDURE [dbo]. [NonRowset]
3920 
3921   (@param1 NVARCHAR(15))
3922 
3923 AS
3924 
3925 BEGIN
3926 
3927   SET NOCOUNT ON;
3928 
3929    DECLARE @count int
3930 
3931    SELECT @count = COUNT(*)FROM Customers
3932 
3933    WHERECustomers.Region = @Param1
3934 
3935    RETURN @count
3936 
3937 END
3938 
3939  
3940 
3941 我们只要把这个存储过程拖到O/R设计器内,它自动生成了以下代码段:
3942 
3943  
3944 
3945 [Function(Name = "dbo.[Customers CountBy Region]")]
3946 
3947 public intCustomers_Count_By_Region([Parameter
3948 
3949 (DbType = "NVarChar (15)")]string param1)
3950 
3951 {
3952 
3953   IExecuteResult result = this.ExecuteMethodCall(this,
3954 
3955   ((MethodInfo) (MethodInfo.GetCurrentMethod())), param1);
3956 
3957   return ((int) (result.ReturnValue));
3958 
3959 }
3960 
3961  
3962 
3963 我们需要时,直接调用就可以了,例如:
3964 
3965  
3966 
3967 int count = db.CustomersCountByRegion("WA");
3968 
3969 Console.WriteLine(count);
3970 
3971  
3972 
3973 语句描述:这个实例使用存储过程返回在“WA”地区的客户数。
3974 
3975  
3976 
3977 2.单一结果集
3978  
3979 
3980 从数据库中返回行集合,并包含用于筛选结果的输入参数。当我们执行 返回行集合的存储过程时,会用到结果类,它存储从存储过程中返回的结果。
3981 
3982  
3983 
3984 下面的示例表示一个存储过程,该存储过程返回客户行并使用输入参数来仅返回将“London”列为客户城市的那些行的固定几列。 
3985 
3986  
3987 
3988 ALTER PROCEDURE [dbo].[Customers By City]
3989 
3990    -- Add the parameters for the stored procedure here
3991 
3992    (@param1 NVARCHAR(20))
3993 
3994 AS
3995 
3996 BEGIN
3997 
3998    -- SET NOCOUNT ON added to prevent extra result sets from
3999 
4000    -- interfering with SELECT statements.
4001 
4002    SET NOCOUNT ON;
4003 
4004    SELECT CustomerID, ContactName, CompanyName, City from
4005 
4006    Customers as c where c.City=@param1
4007 
4008 END
4009 
4010  
4011 
4012 拖到O/R设计器内,它自动生成了以下代码段:
4013 
4014  
4015 
4016 [Function(Name="dbo.[Customers ByCity]")]
4017 
4018 publicISingleResult<Customers_By_CityResult> Customers_By_City(
4019 
4020 [Parameter(DbType="NVarChar(20)")]string param1)
4021 
4022 {
4023 
4024   IExecuteResult result = this.ExecuteMethodCall(this, (
4025 
4026   (MethodInfo) (MethodInfo.GetCurrentMethod())), param1);
4027 
4028   return ((ISingleResult<Customers_By_CityResult>)
4029 
4030    (result.ReturnValue));
4031 
4032 }
4033 
4034  
4035 
4036 我们用下面的代码调用:
4037 
4038  
4039 
4040 ISingleResult<Customers_By_CityResult>result =
4041 
4042 db.Customers_By_City("London");
4043 
4044 foreach (Customers_By_CityResult cust inresult)
4045 
4046 {
4047 
4048    Console.WriteLine("CustID={0}; City={1}",cust.CustomerID,
4049 
4050     cust.City);
4051 
4052 }
4053 
4054  
4055 
4056 语句描述:这个实例使用存储过程返回在伦敦的客户的 CustomerID和City。
4057 
4058  
4059 
4060 3.多个可能形状的单一结果集
4061  
4062 
4063 当存储过程可以返回多个结果形状时,返回类型无法强类型化为单个投影形状。尽管 LINQ to SQL 可以生成所有可能的投影类型,但它无法获知将以何种顺序返回它们。 ResultTypeAttribute 属性适用于返回多个结果类型的存储过程,用以指定该过程可以返回的类型的集合。
4064 
4065  
4066 
4067 在下面的 SQL 代码示例中,结果形状取决于输入(param1 = 1或param1 = 2)。我们不知道先返回哪个投影。
4068 
4069  
4070 
4071 ALTER PROCEDURE [dbo].[SingleRowset_MultiShape]
4072 
4073    -- Add the parameters for the stored procedure here
4074 
4075    (@param1 int )
4076 
4077 AS
4078 
4079 BEGIN
4080 
4081    -- SET NOCOUNT ON added to prevent extra result sets from
4082 
4083    -- interfering with SELECT statements.
4084 
4085    SET NOCOUNT ON;
4086 
4087    if(@param1 = 1)
4088 
4089    SELECT * from Customers as c where c.Region = 'WA'
4090 
4091    else if (@param1 = 2)
4092 
4093    SELECT CustomerID, ContactName, CompanyName from
4094 
4095    Customers as c where c.Region = 'WA'
4096 
4097 END
4098 
4099  
4100 
4101 拖到O/R 设计器内,它自动生成了以下代码段:
4102 
4103  
4104 
4105 [Function (Name="dbo.[Whole Or PartialCustomers Set]")]
4106 
4107 publicISingleResult<Whole_Or_Partial_Customers_SetResult>
4108 
4109 Whole_Or_Partial_Customers_Set([Parameter(DbType="Int")]
4110 
4111 System.Nullable<int> param1)
4112 
4113 {
4114 
4115    IExecuteResult result = this.ExecuteMethodCall(this,
4116 
4117    ((MethodInfo)(MethodInfo.GetCurrentMethod())), param1);
4118 
4119    return ((ISingleResult<Whole_Or_Partial_Customers_SetResult>)
4120 
4121   (result.ReturnValue));
4122 
4123 }
4124 
4125  
4126 
4127 但是,VS2008会把多结果集存储过程识别为单结果集的存储过程,默认生成的代码我们要手动修改一下,要求返回多个结果集,像这样:
4128 
4129  
4130 
4131 [Function(Name="dbo.[Whole Or PartialCustomers Set]")]
4132 
4133 [ResultType(typeof (WholeCustomersSetResult))]
4134 
4135 [ResultType(typeof(PartialCustomersSetResult))]
4136 
4137 public IMultipleResultsWhole_Or_Partial_Customers_Set([Parameter
4138 
4139 (DbType="Int")]System.Nullable<int> param1)
4140 
4141 {
4142 
4143   IExecuteResult result = this.ExecuteMethodCall(this,
4144 
4145    ((MethodInfo)(MethodInfo.GetCurrentMethod())), param1);
4146 
4147    return ((IMultipleResults)(result.ReturnValue));
4148 
4149 }
4150 
4151  
4152 
4153 我们分别定义了两个分部类,用于指定返回的类型。WholeCustomersSetResult类 如 下:
4154 
4155  
4156 
4157 public partial classWholeCustomersSetResult
4158 
4159 {
4160 
4161   private string _CustomerID;
4162 
4163   private string _CompanyName;
4164 
4165   private string _ContactName;
4166 
4167   private string _ContactTitle;
4168 
4169   private string _Address;
4170 
4171    private string _City;
4172 
4173   private string _Region;
4174 
4175    private string _PostalCode;
4176 
4177   private string _Country;
4178 
4179   private string _Phone;
4180 
4181   private string _Fax;
4182 
4183   public WholeCustomersSetResult()
4184 
4185   {
4186 
4187   }
4188 
4189   [Column (Storage = "_CustomerID", DbType ="NChar(5)")]
4190 
4191   public string CustomerID
4192 
4193   {
4194 
4195     get { return this._CustomerID; }
4196 
4197     set
4198 
4199     {
4200 
4201        if ((this._CustomerID != value))
4202 
4203         this._CustomerID = value;
4204 
4205     }
4206 
4207   }
4208 
4209   [Column(Storage = "_CompanyName", DbType ="NVarChar(40)")]
4210 
4211   public string CompanyName
4212 
4213   {
4214 
4215     get { return this._CompanyName; }
4216 
4217     set
4218 
4219     {
4220 
4221        if ((this._CompanyName != value))
4222 
4223          this._CompanyName = value;
4224 
4225     }
4226 
4227   }
4228 
4229   [Column (Storage = "_ContactName", DbType ="NVarChar(30) ")]
4230 
4231   public string ContactName
4232 
4233   {
4234 
4235      get { return this._ContactName; }
4236 
4237     set
4238 
4239     {
4240 
4241       if ((this._ContactName != value))
4242 
4243          this._ContactName = value;
4244 
4245     }
4246 
4247   }
4248 
4249   [Column (Storage = "_ContactTitle", DbType ="NVarChar(30) ")]
4250 
4251   public string ContactTitle
4252 
4253   {
4254 
4255      get { return this._ContactTitle; }
4256 
4257     set
4258 
4259     {
4260 
4261       if ((this._ContactTitle != value))
4262 
4263          this._ContactTitle = value;
4264 
4265     }
4266 
4267   }
4268 
4269    [Column(Storage = "_Address", DbType = "NVarChar(60)")]
4270 
4271   public string Address
4272 
4273   {
4274 
4275     get { return this._Address; }
4276 
4277     set
4278 
4279     {
4280 
4281       if ((this._Address != value))
4282 
4283         this._Address = value;
4284 
4285     }
4286 
4287   }
4288 
4289   [Column(Storage = "_City", DbType = "NVarChar(15)")]
4290 
4291   public string City
4292 
4293   {
4294 
4295     get { return this._City; }
4296 
4297     set
4298 
4299     {
4300 
4301       if ((this._City != value))
4302 
4303         this._City = value;
4304 
4305     }
4306 
4307   }
4308 
4309   [Column(Storage = "_Region", DbType = "NVarChar(15)")]
4310 
4311   public string Region
4312 
4313   {
4314 
4315     get { return this._Region; }
4316 
4317     set
4318 
4319     {
4320 
4321       if ((this._Region != value))
4322 
4323         this._Region = value;
4324 
4325     }
4326 
4327   }
4328 
4329   [Column(Storage = "_PostalCode", DbType ="NVarChar(10)")]
4330 
4331    public string PostalCode
4332 
4333   {
4334 
4335     get { return this._PostalCode; }
4336 
4337     set
4338 
4339     {
4340 
4341        if ((this._PostalCode != value))
4342 
4343         this._PostalCode = value;
4344 
4345     }
4346 
4347   }
4348 
4349   [Column(Storage = "_Country", DbType ="NVarChar(15)")]
4350 
4351    public string Country
4352 
4353   {
4354 
4355     get { return this._Country; }
4356 
4357     set
4358 
4359     {
4360 
4361       if ((this._Country != value))
4362 
4363         this._Country = value;
4364 
4365     }
4366 
4367   }
4368 
4369   [Column(Storage = "_Phone", DbType ="NVarChar(24)")]
4370 
4371    public string Phone
4372 
4373   {
4374 
4375     get { return this._Phone; }
4376 
4377     set
4378 
4379     {
4380 
4381       if ((this._Phone != value))
4382 
4383         this._Phone = value;
4384 
4385     }
4386 
4387   }
4388 
4389   [Column(Storage = "_Fax", DbType ="NVarChar(24)")]
4390 
4391   public string Fax
4392 
4393   {
4394 
4395     get { return this._Fax; }
4396 
4397     set
4398 
4399     {
4400 
4401       if ((this._Fax != value))
4402 
4403         this._Fax = value;
4404 
4405     }
4406 
4407   }
4408 
4409 }
4410 
4411  
4412 
4413 PartialCustomersSetResult类 如下:
4414 
4415  
4416 
4417 public partial classPartialCustomersSetResult
4418 
4419 {
4420 
4421   private string _CustomerID;
4422 
4423   private string _ContactName;
4424 
4425   private string _CompanyName;
4426 
4427   public PartialCustomersSetResult()
4428 
4429   {
4430 
4431   }
4432 
4433   [Column (Storage = "_CustomerID", DbType ="NChar(5)")]
4434 
4435   public string CustomerID
4436 
4437   {
4438 
4439     get { return this._CustomerID; }
4440 
4441     set
4442 
4443     {
4444 
4445        if ((this._CustomerID != value))
4446 
4447         this._CustomerID = value;
4448 
4449     }
4450 
4451   }
4452 
4453   [Column(Storage = "_ContactName", DbType ="NVarChar(30)")]
4454 
4455   public string ContactName
4456 
4457   {
4458 
4459     get { return this._ContactName; }
4460 
4461     set
4462 
4463     {
4464 
4465        if ((this._ContactName != value))
4466 
4467          this._ContactName = value;
4468 
4469     }
4470 
4471   }
4472 
4473   [Column (Storage = "_CompanyName", DbType ="NVarChar(40) ")]
4474 
4475   public string CompanyName
4476 
4477   {
4478 
4479      get { return this._CompanyName; }
4480 
4481     set
4482 
4483     {
4484 
4485       if ((this._CompanyName != value))
4486 
4487          this._CompanyName = value;
4488 
4489     }
4490 
4491   }
4492 
4493 }
4494 
4495  
4496 
4497 这样就可以使用了,下面代码直接调用,分别返回各自的结果集合。
4498 
4499  
4500 
4501 //返回全部Customer结果集
4502 
4503 IMultipleResults result =db.Whole_Or_Partial_Customers_Set(1);
4504 
4505 IEnumerable<WholeCustomersSetResult>shape1 =
4506 
4507 result.GetResult<WholeCustomersSetResult>();
4508 
4509 foreach (WholeCustomersSetResult compNamein shape1)
4510 
4511 {
4512 
4513    Console.WriteLine(compName.CompanyName);
4514 
4515 }
4516 
4517 //返回部分 Customer结果集
4518 
4519 result =db.Whole_Or_Partial_Customers_Set(2);
4520 
4521 IEnumerable<PartialCustomersSetResult>shape2 =
4522 
4523 result.GetResult<PartialCustomersSetResult>();
4524 
4525 foreach (PartialCustomersSetResult con inshape2)
4526 
4527 {
4528 
4529    Console.WriteLine(con.ContactName);
4530 
4531 }
4532 
4533  
4534 
4535 语句描述:这个实例使用存储过程返回“WA”地区中的一组客户。返回的结果集形状取决于传入的参数。如果参数等于 1,则返回所有客户属性。如果参数等于2,则返回ContactName属性。
4536 
4537  
4538 
4539 4.多个结果集
4540  
4541 
4542 这种存储过程可以生成多个结果形状,但我们已经知道结果的返回顺序。
4543 
4544  
4545 
4546 下面是一个按顺序返回多个结果集的存储过程Get Customer And Orders。 返回顾客ID为"SEVES"的顾客和他们所有的订单。
4547 
4548  
4549 
4550 ALTER PROCEDURE [dbo].[Get Customer AndOrders]
4551 
4552 (@CustomerID nchar(5))
4553 
4554   -- Add the parameters for the stored procedure here
4555 
4556 AS
4557 
4558 BEGIN
4559 
4560    -- SET NOCOUNT ON added to prevent extra result sets from
4561 
4562   -- interfering with SELECT statements.
4563 
4564   SET NOCOUNT ON;
4565 
4566    SELECT * FROM Customers AS c WHERE c.CustomerID = @CustomerID 
4567 
4568   SELECT * FROM Orders AS o WHERE o.CustomerID = @CustomerID
4569 
4570 END
4571 
4572  
4573 
4574 拖到设计器代码如下:
4575 
4576  
4577 
4578 [Function (Name="dbo.[Get Customer AndOrders]")]
4579 
4580 publicISingleResult<Get_Customer_And_OrdersResult>
4581 
4582 Get_Customer_And_Orders([Parameter(Name="CustomerID",
4583 
4584 DbType="NChar(5)")] stringcustomerID)
4585 
4586 {
4587 
4588    IExecuteResult result = this.ExecuteMethodCall(this,
4589 
4590    ((MethodInfo)(MethodInfo.GetCurrentMethod())), customerID);
4591 
4592    return ((ISingleResult<Get_Customer_And_OrdersResult>)
4593 
4594    (result.ReturnValue));
4595 
4596 }
4597 
4598  
4599 
4600 同样,我们要修改自动生成的代码:
4601 
4602  
4603 
4604 [Function(Name="dbo.[Get Customer AndOrders] ")]
4605 
4606 [ResultType(typeof(CustomerResultSet))]
4607 
4608 [ResultType(typeof(OrdersResultSet))]
4609 
4610 public IMultipleResultsGet_Customer_And_Orders
4611 
4612 ([Parameter(Name="CustomerID",DbType="NChar(5)")]
4613 
4614 string customerID)
4615 
4616 {
4617 
4618   IExecuteResult result = this.ExecuteMethodCall(this,
4619 
4620   ((MethodInfo) (MethodInfo.GetCurrentMethod())), customerID);
4621 
4622   return ((IMultipleResults)(result.ReturnValue));
4623 
4624 }
4625 
4626  
4627 
4628 同样,自己手写类,让其存储过程返回各自的结果集。
4629 
4630  
4631 
4632 CustomerResultSet类
4633 
4634  
4635 
4636 public partial class CustomerResultSet
4637 
4638 {
4639 
4640   private string _CustomerID;
4641 
4642   private string _CompanyName;
4643 
4644   private string _ContactName;
4645 
4646   private string _ContactTitle;
4647 
4648   private string _Address;
4649 
4650    private string _City;
4651 
4652   private string _Region;
4653 
4654    private string _PostalCode;
4655 
4656   private string _Country;
4657 
4658   private string _Phone;
4659 
4660   private string _Fax;
4661 
4662   public CustomerResultSet()
4663 
4664   {
4665 
4666   }
4667 
4668   [Column(Storage = "_CustomerID", DbType ="NChar(5)")]
4669 
4670    public string CustomerID
4671 
4672   {
4673 
4674     get { return this._CustomerID; }
4675 
4676     set
4677 
4678     {
4679 
4680        if ((this._CustomerID != value))
4681 
4682         this._CustomerID = value;
4683 
4684     }
4685 
4686   }
4687 
4688   [Column(Storage = "_CompanyName", DbType ="NVarChar(40)")]
4689 
4690   public string CompanyName
4691 
4692   {
4693 
4694     get { return this._CompanyName; }
4695 
4696     set
4697 
4698     {
4699 
4700        if ((this._CompanyName != value))
4701 
4702          this._CompanyName = value;
4703 
4704     }
4705 
4706   }
4707 
4708   [Column (Storage = "_ContactName", DbType ="NVarChar(30) ")]
4709 
4710   public string ContactName
4711 
4712   {
4713 
4714      get { return this._ContactName; }
4715 
4716     set
4717 
4718     {
4719 
4720       if ((this._ContactName != value))
4721 
4722          this._ContactName = value;
4723 
4724     }
4725 
4726   }
4727 
4728   [Column (Storage = "_ContactTitle", DbType ="NVarChar(30) ")]
4729 
4730   public string ContactTitle
4731 
4732   {
4733 
4734      get { return this._ContactTitle; }
4735 
4736     set
4737 
4738     {
4739 
4740       if ((this._ContactTitle != value))
4741 
4742          this._ContactTitle = value;
4743 
4744     }
4745 
4746   }
4747 
4748    [Column(Storage = "_Address", DbType = "NVarChar(60)")]
4749 
4750   public string Address
4751 
4752   {
4753 
4754     get { return this._Address; }
4755 
4756     set
4757 
4758     {
4759 
4760       if ((this._Address != value))
4761 
4762         this._Address = value;
4763 
4764     }
4765 
4766   }
4767 
4768   [Column(Storage = "_City", DbType ="NVarChar(15)")]
4769 
4770   public string City
4771 
4772   {
4773 
4774     get { return this._City; }
4775 
4776     set
4777 
4778     {
4779 
4780       if ((this._City != value))
4781 
4782         this._City = value;
4783 
4784     }
4785 
4786   }
4787 
4788   [Column(Storage = "_Region", DbType = "NVarChar(15)")]
4789 
4790   public string Region
4791 
4792   {
4793 
4794     get { return this._Region; }
4795 
4796     set
4797 
4798     {
4799 
4800       if ((this._Region != value))
4801 
4802         this._Region = value;
4803 
4804     }
4805 
4806   }
4807 
4808   [Column(Storage = "_PostalCode", DbType ="NVarChar(10)")]
4809 
4810    public string PostalCode
4811 
4812   {
4813 
4814     get { return this._PostalCode; }
4815 
4816     set
4817 
4818     {
4819 
4820        if ((this._PostalCode != value))
4821 
4822         this._PostalCode = value;
4823 
4824     }
4825 
4826   }
4827 
4828   [Column(Storage = "_Country", DbType ="NVarChar(15)")]
4829 
4830    public string Country
4831 
4832   {
4833 
4834     get { return this._Country; }
4835 
4836     set
4837 
4838     {
4839 
4840       if ((this._Country != value))
4841 
4842         this._Country = value;
4843 
4844     }
4845 
4846   }
4847 
4848   [Column(Storage = "_Phone", DbType ="NVarChar(24)")]
4849 
4850    public string Phone
4851 
4852   {
4853 
4854     get { return this._Phone; }
4855 
4856     set
4857 
4858     {
4859 
4860       if ((this._Phone != value))
4861 
4862         this._Phone = value;
4863 
4864     }
4865 
4866   }
4867 
4868   [Column(Storage = "_Fax", DbType ="NVarChar(24)")]
4869 
4870   public string Fax
4871 
4872   {
4873 
4874     get { return this._Fax; }
4875 
4876     set
4877 
4878     {
4879 
4880       if ((this._Fax != value))
4881 
4882         this._Fax = value;
4883 
4884     }
4885 
4886   }
4887 
4888 }
4889 
4890  
4891 
4892 OrdersResultSet 类
4893 
4894  
4895 
4896 public partial class OrdersResultSet
4897 
4898 {
4899 
4900   private System.Nullable<int> _OrderID;
4901 
4902   private string _CustomerID;
4903 
4904   private System.Nullable<int> _EmployeeID;
4905 
4906   private System.Nullable<System.DateTime> _OrderDate;
4907 
4908   private System.Nullable<System.DateTime> _RequiredDate;
4909 
4910   private System.Nullable<System.DateTime> _ShippedDate;
4911 
4912   private System.Nullable<int> _ShipVia;
4913 
4914   private System.Nullable<decimal> _Freight;
4915 
4916    private string _ShipName;
4917 
4918   private string _ShipAddress;
4919 
4920   private string _ShipCity;
4921 
4922   private string _ShipRegion;
4923 
4924   private string _ShipPostalCode;
4925 
4926   private string _ShipCountry;
4927 
4928   public OrdersResultSet()
4929 
4930   {
4931 
4932   }
4933 
4934   [Column(Storage = "_OrderID", DbType = "Int")]
4935 
4936   public System.Nullable<int> OrderID
4937 
4938   {
4939 
4940     get { return this._OrderID; }
4941 
4942     set
4943 
4944     {
4945 
4946       if ((this._OrderID != value))
4947 
4948         this._OrderID = value;
4949 
4950     }
4951 
4952   }
4953 
4954   [Column(Storage = "_CustomerID", DbType ="NChar(5)")]
4955 
4956   public string CustomerID
4957 
4958   {
4959 
4960     get { return this._CustomerID; }
4961 
4962     set
4963 
4964     {
4965 
4966       if ((this._CustomerID != value))
4967 
4968         this._CustomerID = value;
4969 
4970     }
4971 
4972   }
4973 
4974    [Column(Storage = "_EmployeeID", DbType ="Int")]
4975 
4976   public System.Nullable<int> EmployeeID
4977 
4978   {
4979 
4980     get { return this._EmployeeID; }
4981 
4982     set
4983 
4984     {
4985 
4986       if ((this._EmployeeID != value))
4987 
4988         this._EmployeeID = value;
4989 
4990     }
4991 
4992   }
4993 
4994    [Column(Storage = "_OrderDate", DbType ="DateTime")]
4995 
4996   public System.Nullable<System.DateTime> OrderDate
4997 
4998   {
4999 
5000     get { return this._OrderDate; }
5001 
5002     set
5003 
5004     {
5005 
5006       if ((this._OrderDate != value))
5007 
5008          this._OrderDate = value;
5009 
5010     }
5011 
5012   }
5013 
5014   [Column (Storage = "_RequiredDate", DbType ="DateTime")]
5015 
5016   public System.Nullable<System.DateTime> RequiredDate
5017 
5018   {
5019 
5020     get { return this._RequiredDate; }
5021 
5022     set
5023 
5024     {
5025 
5026       if ((this._RequiredDate != value))
5027 
5028          this._RequiredDate = value;
5029 
5030     }
5031 
5032   }
5033 
5034    [Column(Storage = "_ShippedDate", DbType ="DateTime")]
5035 
5036   public System.Nullable<System.DateTime> ShippedDate
5037 
5038   {
5039 
5040     get { return this._ShippedDate; }
5041 
5042     set
5043 
5044      {
5045 
5046       if ((this._ShippedDate != value))
5047 
5048         this._ShippedDate = value;
5049 
5050     }
5051 
5052   }
5053 
5054    [Column(Storage = "_ShipVia", DbType = "Int")]
5055 
5056   public System.Nullable<int> ShipVia
5057 
5058   {
5059 
5060     get { return this._ShipVia; }
5061 
5062     set
5063 
5064     {
5065 
5066       if ((this._ShipVia != value))
5067 
5068          this._ShipVia = value;
5069 
5070     }
5071 
5072   }
5073 
5074   [Column (Storage = "_Freight", DbType ="Money")]
5075 
5076   public System.Nullable<decimal> Freight
5077 
5078   {
5079 
5080     get { return this._Freight; }
5081 
5082     set
5083 
5084     {
5085 
5086       if ((this._Freight != value))
5087 
5088          this._Freight = value;
5089 
5090     }
5091 
5092   }
5093 
5094   [Column (Storage = "_ShipName", DbType ="NVarChar(40)")]
5095 
5096   public string ShipName
5097 
5098   {
5099 
5100     get { return this._ShipName; }
5101 
5102     set
5103 
5104     {
5105 
5106       if ((this._ShipName != value))
5107 
5108         this._ShipName = value;
5109 
5110     }
5111 
5112   }
5113 
5114   [Column(Storage = "_ShipAddress", DbType ="NVarChar(60)")]
5115 
5116   public string ShipAddress
5117 
5118   {
5119 
5120     get { return this._ShipAddress; }
5121 
5122     set
5123 
5124     {
5125 
5126        if ((this._ShipAddress != value))
5127 
5128          this._ShipAddress = value;
5129 
5130     }
5131 
5132   }
5133 
5134   [Column (Storage = "_ShipCity", DbType ="NVarChar(15)")]
5135 
5136   public string ShipCity
5137 
5138   {
5139 
5140     get { return this._ShipCity; }
5141 
5142     set
5143 
5144     {
5145 
5146       if ((this._ShipCity != value))
5147 
5148         this._ShipCity = value;
5149 
5150     }
5151 
5152   }
5153 
5154   [Column(Storage = "_ShipRegion", DbType ="NVarChar(15)")]
5155 
5156    public string ShipRegion
5157 
5158   {
5159 
5160     get { return this._ShipRegion; }
5161 
5162     set
5163 
5164     {
5165 
5166        if ((this._ShipRegion != value))
5167 
5168         this._ShipRegion = value;
5169 
5170     }
5171 
5172   }
5173 
5174   [Column(Storage = "_ShipPostalCode", DbType ="NVarChar(10)")]
5175 
5176   public string ShipPostalCode
5177 
5178   {
5179 
5180     get { return this._ShipPostalCode; }
5181 
5182     set
5183 
5184     {
5185 
5186       if ((this._ShipPostalCode != value))
5187 
5188          this._ShipPostalCode = value;
5189 
5190     }
5191 
5192   }
5193 
5194    [Column(Storage = "_ShipCountry", DbType = "NVarChar(15)")]
5195 
5196   public string ShipCountry
5197 
5198   {
5199 
5200     get { return this._ShipCountry; }
5201 
5202     set
5203 
5204     {
5205 
5206       if ((this._ShipCountry != value))
5207 
5208          this._ShipCountry = value;
5209 
5210     }
5211 
5212   }
5213 
5214 }
5215 
5216  
5217 
5218  
5219 
5220 这时,只要调用就可以了。
5221 
5222  
5223 
5224 IMultipleResults result =db.Get_Customer_And_Orders("SEVES");
5225 
5226 //返回 Customer结果集
5227 
5228 IEnumerable<CustomerResultSet>customer =
5229 
5230 result.GetResult<CustomerResultSet>();
5231 
5232 //返回Orders结果集
5233 
5234 IEnumerable<OrdersResultSet> orders =
5235 
5236 result.GetResult<OrdersResultSet>();
5237 
5238 //在这里,我们读取CustomerResultSet中的数据
5239 
5240 foreach (CustomerResultSet cust incustomer)
5241 
5242 {
5243 
5244   Console.WriteLine(cust.CustomerID);
5245 
5246 }
5247 
5248  
5249 
5250 语句描述:这个实例使用存储过程返回客户“SEVES”及其所有订单。
5251 
5252  
5253 
5254 5.带输出参数
5255  
5256 
5257 LINQ to SQL 将输出参数映射到引用参数 ,并且对于值类型,它将参数声明为可以为null。
5258 
5259  
5260 
5261 下面的示例带有单个输入参数(客户 ID)并返回一个输出参数(该客户的总销售额)。
5262 
5263  
5264 
5265 ALTER PROCEDURE [dbo].[CustOrderTotal]
5266 
5267 @CustomerID nchar(5),
5268 
5269 @TotalSales money OUTPUT
5270 
5271 AS
5272 
5273 SELECT @TotalSales =SUM(OD.UNITPRICE*(1-OD.DISCOUNT) * OD.QUANTITY)
5274 
5275 FROM ORDERS O, "ORDER DETAILS" OD
5276 
5277 where O.CUSTOMERID = @CustomerID AND O.ORDERID= OD.ORDERID
5278 
5279  
5280 
5281 把这个存储过程拖到设计器中,图片如下:
5282 
5283  
5284 
5285  
5286 
5287 其生成代码如下:
5288 
5289  
5290 
5291 [Function(Name="dbo.CustOrderTotal")]
5292 
5293 public int CustOrderTotal (
5294 
5295 [Parameter(Name="CustomerID",DbType="NChar(5) ")]string customerID,
5296 
5297 [Parameter (Name="TotalSales",DbType="Money")]
5298 
5299  ref System.Nullable<decimal> totalSales)
5300 
5301 {
5302 
5303    IExecuteResult result = this.ExecuteMethodCall(this,
5304 
5305    ((MethodInfo)(MethodInfo.GetCurrentMethod())),
5306 
5307   customerID, totalSales);
5308 
5309   totalSales = ((System.Nullable<decimal>)
5310 
5311   (result.GetParameterValue(1)));
5312 
5313   return ((int) (result.ReturnValue));
5314 
5315 }
5316 
5317  
5318 
5319 我们使用下面的语句调用此存储过程:注意:输出参数是按引用传递的,以支持参数为“in/out”的方案。在这种情况下,参数仅为“out”。
5320 
5321  
5322 
5323 decimal? totalSales = 0;
5324 
5325 string customerID = "ALFKI";
5326 
5327 db.CustOrderTotal(customerID, reftotalSales);
5328 
5329 Console.WriteLine("Total Sales forCustomer '{0}' = {1:C}",
5330 
5331 customerID, totalSales);
5332 
5333  
5334 
5335 语句描述:这个实例使用返回 Out 参数的存储过程。
5336 
5337  
5338 
5339 好了,就说到这里了,其增删改操作同理。相信大家通过这5个实例理解了存储过程。
5340 
5341  
5342 
5343 LINQ to SQL语句(21)之用户定义函数
5344 用户定义函数
5345 
5346  
5347 
5348 我们可以在LINQ to SQL中使用用户定义函数。只要把用户定义函数拖到O/R设计器中,LINQ to SQL自动使用FunctionAttribute属性和ParameterAttribute属性(如果需要)将其函数指定为方法。这时,我们只需简单调用即可。
5349 
5350  
5351 
5352 在这里注意:使用用户定义函数的时候必须满足以下形式之一,否则会出现InvalidOperationException异常情况。
5353 
5354  
5355 
5356 具有正确映射属性的方法调用的函数。这里使用FunctionAttribute属性和 ParameterAttribute属性。
5357 
5358  
5359 
5360 特定于LINQ to SQL的静态SQL方法。
5361 
5362  
5363 
5364 .NET Framework方法支持的函数。
5365 
5366  
5367 
5368 下面介绍几个例子:
5369 
5370  
5371 
5372 1.在Select中使用用户定义的标量函数
5373  
5374 
5375 所谓标量函数是指返回在 RETURNS 子句中定义的类型的单个数据值。可以使用所有标量数据类型,包括 bigint 和 sql_variant。不支持 timestamp 数据类型、用户定义数据类型和非标量类型(如 table 或 cursor)。在 BEGIN...END 块中定义的函数主体包含返回该值的 Transact-SQL 语句系列。返回类型可以是除 text、ntext、image 、cursor 和 timestamp 之外的任何数据类型。我们在系统自带的 NORTHWND.MDF数据库中,有3个自定义函数,这里使用  TotalProductUnitPriceByCategory,其代码如下:
5376 
5377  
5378 
5379 ALTER FUNCTION[dbo].[TotalProductUnitPriceByCategory]
5380 
5381 (@categoryID int)
5382 
5383 RETURNS Money
5384 
5385 AS
5386 
5387 BEGIN
5388 
5389   -- Declare the return variable here
5390 
5391   DECLARE @ResultVar Money
5392 
5393   -- Add the T-SQL statements to compute the return value here
5394 
5395   SELECT @ResultVar = (Select SUM(UnitPrice)
5396 
5397             from Products
5398 
5399             where CategoryID = @categoryID)
5400 
5401   -- Return the result of the function
5402 
5403   RETURN @ResultVar
5404 
5405 END
5406 
5407  
5408 
5409 我们将其拖到设计器中,LINQ to SQL通过使用 FunctionAttribute 属性将类中定义的客户端方法映射到用户定义的函数。请注意,这个方法体会构造一个捕获方法调用意向的表达式,并将该表达式传递给 DataContext 进行转换和执行。
5410 
5411  
5412 
5413 [Function(Name="dbo.TotalProductUnitPriceByCategory",
5414 
5415 IsComposable=true)]
5416 
5417 public System.Nullable<decimal>TotalProductUnitPriceByCategory(
5418 
5419 [Parameter (DbType="Int")]System.Nullable<int> categoryID)
5420 
5421 {
5422 
5423   return ((System.Nullable<decimal>)(this.ExecuteMethodCall(this,
5424 
5425   ((MethodInfo) (MethodInfo.GetCurrentMethod())), categoryID)
5426 
5427    .ReturnValue));
5428 
5429 }
5430 
5431  
5432 
5433 我们使用时,可以用以下代码来调用:
5434 
5435  
5436 
5437 var q = from c in db.Categories
5438 
5439     select new
5440 
5441     {
5442 
5443       c.CategoryID,
5444 
5445        TotalUnitPrice =
5446 
5447          db.TotalProductUnitPriceByCategory(c.CategoryID)
5448 
5449     };
5450 
5451  
5452 
5453 这时,LINQ to SQL自动生成SQL语句如下:
5454 
5455  
5456 
5457 SELECT [t0].[CategoryID],CONVERT(Decimal(29,4),
5458 
5459 [dbo].[TotalProductUnitPriceByCategory]([t0].[CategoryID]))
5460 
5461 AS [TotalUnitPrice] FROM [dbo].[Categories]AS [t0]
5462 
5463 2.在Where从句中 使用用户定义的标量函数
5464 这个例子使用方法同上一个例子原理基本相同了,MinUnitPriceByCategory自定义函数如下:
5465 
5466  
5467 
5468 ALTER FUNCTION[dbo].[MinUnitPriceByCategory]
5469 
5470 (@categoryID INT
5471 
5472 )
5473 
5474 RETURNS Money
5475 
5476 AS
5477 
5478 BEGIN
5479 
5480   -- Declare the return variable here
5481 
5482   DECLARE @ResultVar Money
5483 
5484   -- Add the T -SQL statements to compute the return value here
5485 
5486   SELECT @ResultVar = MIN(p.UnitPrice) FROM Products as p
5487 
5488   WHERE p.CategoryID = @categoryID
5489 
5490   -- Return the result of the function
5491 
5492   RETURN @ResultVar
5493 
5494 END
5495 
5496  
5497 
5498 拖到设计器中,生成代码如下:
5499 
5500  
5501 
5502 [Function (Name="dbo.MinUnitPriceByCategory",IsComposable=true)]
5503 
5504 public System.Nullable<decimal>MinUnitPriceByCategory(
5505 
5506 [Parameter(DbType="Int")]System.Nullable<int> categoryID)
5507 
5508 {
5509 
5510   return ((System.Nullable<decimal>) (this.ExecuteMethodCall(
5511 
5512   this, ((MethodInfo) (MethodInfo.GetCurrentMethod())),
5513 
5514    categoryID).ReturnValue));
5515 
5516 }
5517 
5518  
5519 
5520 这时可以使用了:注意这里在 LINQ to SQL 查询中,对生成的用户定义函数方法 MinUnitPriceByCategory的内联调用。此函数不会立即执行,这是因为查询会延 迟执行。延迟执行的查询中包含的函数直到此查询执行时才会执行。为此查询生成的 SQL 会转换成对数据库中用户定义函数的调用(请参见此查询后面的生成的 SQL语句),当在查询外部调用这个函数时,LINQ to SQL 会用方法调用表达式创建一个简单查询并执行。 
5521 
5522  
5523 
5524 var q =
5525 
5526   from p in db.Products
5527 
5528   where p.UnitPrice ==
5529 
5530    db.MinUnitPriceByCategory(p.CategoryID)
5531 
5532   select p;
5533 
5534  
5535 
5536 它自动生成的SQL语句如下:
5537 
5538  
5539 
5540 SELECT [t0]. [ProductID],[t0].[ProductName], [t0].[SupplierID],
5541 
5542 [t0]. [CategoryID],[t0].[QuantityPerUnit],[t0].[UnitPrice],
5543 
5544 [t0]. [UnitsInStock],[t0].[UnitsOnOrder],[t0].[ReorderLevel],
5545 
5546 [t0]. [Discontinued]FROM [dbo].[Products]AS [t0]
5547 
5548 WHERE [t0]. [UnitPrice] =
5549 
5550 [dbo].[MinUnitPriceByCategory]([t0].[CategoryID])
5551 
5552  
5553 
5554 3.使用用户定义的表值函数
5555  
5556 
5557 表值函数返回单个行集(与存储过程不同,存储过程可返回多个结果形状)。由于表值函数的返回类型为 Table,因此在 SQL 中可以使用表的任何地方均可以使用表值函数。此外,您还可以完全像处理表那样来处理表值函数。
5558 
5559  
5560 
5561 下面的 SQL 用户定义函数显式声明其返回一个 TABLE。因此,隐式定义了所返回的行集结构。
5562 
5563 ALTER FUNCTION[dbo].[ProductsUnderThisUnitPrice]
5564 
5565 (@price Money
5566 
5567 )
5568 
5569 RETURNS TABLE
5570 
5571 AS
5572 
5573 RETURN
5574 
5575   SELECT *
5576 
5577    FROM Products as P
5578 
5579   Where p.UnitPrice < @price
5580 
5581  
5582 
5583 拖到设计器中,LINQ to SQL 按如下方式映射此函数:
5584 
5585  
5586 
5587 [Function(Name="dbo.ProductsUnderThisUnitPrice",
5588 
5589 IsComposable=true)]
5590 
5591 publicIQueryable<ProductsUnderThisUnitPriceResult>
5592 
5593 ProductsUnderThisUnitPrice([Parameter(DbType="Money")]
5594 
5595 System.Nullable<decimal> price)
5596 
5597 {
5598 
5599   return this.CreateMethodCallQuery
5600 
5601    <ProductsUnderThisUnitPriceResult>(this,
5602 
5603   ((MethodInfo) (MethodInfo.GetCurrentMethod())), price);
5604 
5605 }
5606 
5607  
5608 
5609 这时我们小小的修改一下Discontinued属性为可空的bool类型。
5610 
5611  
5612 
5613 private System.Nullable<bool>_Discontinued;
5614 
5615 public System.Nullable<bool>Discontinued
5616 
5617 {
5618 
5619 }
5620 
5621  
5622 
5623 我们可以这样调用使用了:
5624 
5625  
5626 
5627 var q = from p indb.ProductsUnderThisUnitPrice(10.25M)
5628 
5629     where ! (p.Discontinued ?? false)
5630 
5631     select p;
5632 
5633  
5634 
5635 其生成 SQL语句如下:
5636 
5637  
5638 
5639 SELECT [t0].[ProductID],[t0].[ProductName], [t0].[SupplierID],
5640 
5641 [t0].[CategoryID], [t0].[QuantityPerUnit],[t0].[UnitPrice],
5642 
5643 [t0].[UnitsInStock], [t0].[UnitsOnOrder],[t0].[ReorderLevel],
5644 
5645 [t0].[Discontinued]
5646 
5647 FROM [dbo].[ProductsUnderThisUnitPrice](@p0) AS [t0]
5648 
5649 WHERE NOT ((COALESCE([t0].[Discontinued],@p1)) = 1)
5650 
5651 -- @p0: Input Money (Size = 0; Prec = 19;Scale = 4) [10.25]
5652 
5653 -- @p1: Input Int (Size = 0; Prec = 0;Scale = 0) [0]
5654 
5655 4.以联接方式使用用户定义的表值函数
5656  
5657 
5658 我们利用上面的ProductsUnderThisUnitPrice用户定义函数,在 LINQ to SQL 中, 调用如下:
5659 
5660  
5661 
5662 var q =
5663 
5664   from c in db.Categories
5665 
5666   join p in db.ProductsUnderThisUnitPrice(8.50M) on
5667 
5668    c.CategoryID equals p.CategoryID into prods
5669 
5670   from p in prods
5671 
5672   select new
5673 
5674   {
5675 
5676     c.CategoryID,
5677 
5678     c.CategoryName,
5679 
5680     p.ProductName,
5681 
5682      p.UnitPrice
5683 
5684   };
5685 
5686  
5687 
5688 其生成的 SQL 代码说明对此函数返回的表执行联接。
5689 
5690  
5691 
5692 SELECT [t0].[CategoryID], [t0]. [CategoryName],
5693 
5694 [t1].[ProductName], [t1].[UnitPrice]
5695 
5696 FROM [dbo].[Categories] AS [t0]
5697 
5698 CROSS JOIN [dbo].[ProductsUnderThisUnitPrice](@p0) AS [t1]
5699 
5700 WHERE ([t0]. [CategoryID]) =[t1].[CategoryID]
5701 
5702 -- @p0: Input Money (Size = 0; Prec = 19;Scale = 4) [8.50]
5703 
5704  
5705 
5706  
5707 
5708 LINQ to SQL语句(22)之DataContext
5709 DataContext
5710 
5711  
5712 
5713 DataContext作为LINQ to SQL框架的主入口点,为我们 提供了一些方法和属性,本文用几个例子说明DataContext几个典型的应用。
5714 
5715  
5716 
5717 创建和删除数据库
5718  
5719 
5720 CreateDatabase方法用于在服务器上创建数据库。
5721 
5722  
5723 
5724 DeleteDatabase方法用于删除由DataContext连接字符串标识的数据 库。
5725 
5726  
5727 
5728 数据库的名称有以下方法来定义:
5729 
5730  
5731 
5732 如果数据库在连接字符串中标识,则使用该连接字符串的名称。
5733 
5734  
5735 
5736 如果存在DatabaseAttribute属性 (Attribute),则将其Name属性(Property)用作数据库的名称。
5737 
5738  
5739 
5740 如果连接字符串中没有数据库标记,并且使用强类型的DataContext,则会检查与 DataContext继承类名称相同的数据库。如果使用弱类型的DataContext,则会引发异常。
5741 
5742  
5743 
5744 如果已通过使用文件名创建了DataContext,则会创建与该文件名相对应的数据库。
5745 
5746  
5747 
5748 我们首先用实体类描述关系数据库表和列的结构的属性。再调用DataContext的CreateDatabase方法,LINQ to SQL会用我们的定义的实体类结构来构造一个新的数据库实例。还可以通过使用 .mdf 文件或只使用目录名(取决于连接字符串),将 CreateDatabase与SQL Server一起使用。 LINQ to SQL使用连接字符串来定义要创建的数据库和作为数据库创建位置的服务器。
5749 
5750  
5751 
5752 说了这么多,用一段实例说明一下吧!
5753 
5754  
5755 
5756 首先,我们新建一个NewCreateDB类用于创建一个名为NewCreateDB.mdf的新数据库,该数据库有一个Person表,有三个字段,分别为PersonID、PersonName、Age。
5757 
5758  
5759 
5760 public class NewCreateDB : DataContext
5761 
5762 {
5763 
5764   public Table<Person> Persons;
5765 
5766   public NewCreateDB (string connection)
5767 
5768     :
5769 
5770     base(connection)
5771 
5772   {
5773 
5774   }
5775 
5776   public NewCreateDB(System.Data.IDbConnection connection)
5777 
5778     :
5779 
5780     base(connection)
5781 
5782   {
5783 
5784   }
5785 
5786 }
5787 
5788 [Table(Name = "Person")]
5789 
5790 public partial class Person :INotifyPropertyChanged
5791 
5792 {
5793 
5794   private int _PersonID;
5795 
5796   private string _PersonName;
5797 
5798   private System.Nullable<int> _Age;
5799 
5800   public Person() { }
5801 
5802   [Column(Storage = "_PersonID", DbType = "INT",
5803 
5804     IsPrimaryKey = true)]
5805 
5806   public int PersonID
5807 
5808   {
5809 
5810     get { return this._PersonID; }
5811 
5812     set
5813 
5814     {
5815 
5816       if ((this._PersonID != value))
5817 
5818       {
5819 
5820          this.OnPropertyChanged("PersonID");
5821 
5822          this._PersonID = value;
5823 
5824         this.OnPropertyChanged ("PersonID");
5825 
5826       }
5827 
5828     }
5829 
5830   }
5831 
5832   [Column(Storage = "_PersonName", DbType ="NVarChar(30)")]
5833 
5834   public string PersonName
5835 
5836    {
5837 
5838     get { return this._PersonName; }
5839 
5840     set
5841 
5842     {
5843 
5844       if ((this._PersonName != value))
5845 
5846       {
5847 
5848         this.OnPropertyChanged ("PersonName");
5849 
5850         this._PersonName = value;
5851 
5852         this.OnPropertyChanged ("PersonName");
5853 
5854       }
5855 
5856     }
5857 
5858   }
5859 
5860   [Column(Storage = "_Age", DbType = "INT")]
5861 
5862   public System.Nullable<int> Age
5863 
5864   {
5865 
5866     get { return this._Age; }
5867 
5868     set
5869 
5870     {
5871 
5872       if ((this._Age != value))
5873 
5874        {
5875 
5876         this.OnPropertyChanged("Age");
5877 
5878         this._Age = value;
5879 
5880          this.OnPropertyChanged("Age");
5881 
5882       }
5883 
5884     }
5885 
5886   }
5887 
5888   public event PropertyChangedEventHandler PropertyChanged;
5889 
5890   protected virtual void OnPropertyChanged (string PropertyName)
5891 
5892   {
5893 
5894     if ((this.PropertyChanged != null))
5895 
5896     {
5897 
5898        this.PropertyChanged(this,
5899 
5900         new PropertyChangedEventArgs(PropertyName));
5901 
5902     }
5903 
5904   }
5905 
5906 }
5907 
5908  
5909 
5910 接下来的一段代码先创建一个数据库,在调用 CreateDatabase后,新的数据库就会存在并且会接受一般的查询和命令。接着插入一条记录并且查询。最后删除这个数据库。
5911 
5912  
5913 
5914 //1.新建一个临时 文件夹来存放新建的数据库
5915 
5916 string userTempFolder =Environment.GetEnvironmentVariable
5917 
5918 ("SystemDrive") +@"YJingLee";
5919 
5920 Directory.CreateDirectory (userTempFolder);
5921 
5922 //2.新建数据库NewCreateDB
5923 
5924 string userMDF = System.IO.Path.Combine(userTempFolder,
5925 
5926   @"NewCreateDB.mdf");
5927 
5928 string connStr = String.Format (@"DataSource=.SQLEXPRESS;
5929 
5930 AttachDbFilename={0};IntegratedSecurity=True;
5931 
5932 Connect Timeout=30;User Instance=True;
5933 
5934 Integrated Security = SSPI;",userMDF);
5935 
5936 NewCreateDB newDB = newNewCreateDB(connStr);
5937 
5938 newDB.CreateDatabase();
5939 
5940 //3.插入 数据并查询
5941 
5942 var newRow = new Person
5943 
5944 {
5945 
5946    PersonID = 1,
5947 
5948    PersonName = "YJingLee",
5949 
5950    Age = 22
5951 
5952 };
5953 
5954 newDB.Persons.InsertOnSubmit(newRow);
5955 
5956 newDB.SubmitChanges();
5957 
5958 var q = from x in newDB.Persons
5959 
5960      select x;
5961 
5962 //4.删除数据库
5963 
5964 newDB.DeleteDatabase();
5965 
5966 //5.删除临时目录
5967 
5968 Directory.Delete (userTempFolder);
5969 
5970  
5971 
5972 数据库验证
5973  
5974 
5975 DatabaseExists方法用于 尝试通过使用DataContext中的连接打开数据库,如果成功返回true。
5976 
5977  
5978 
5979 下面代码说明是否存在Northwind数据库和NewCreateDB数据库。
5980 
5981  
5982 
5983 // 检测Northwind数据库是否存在
5984 
5985 if (db.DatabaseExists())
5986 
5987    Console.WriteLine("Northwind数据库存在");
5988 
5989 else
5990 
5991   Console.WriteLine("Northwind数据库不存在");
5992 
5993 //检测 NewCreateDB数据库是否存在
5994 
5995 string userTempFolder =Environment.GetEnvironmentVariable("Temp");
5996 
5997 string userMDF =System.IO.Path.Combine(userTempFolder,
5998 
5999 @"NewCreateDB.mdf");
6000 
6001 NewCreateDB newDB = newNewCreateDB(userMDF);
6002 
6003 if (newDB.DatabaseExists())
6004 
6005    Console.WriteLine("NewCreateDB数据库存在");
6006 
6007 else
6008 
6009   Console.WriteLine("NewCreateDB数据库不存在 ");
6010 
6011  
6012 
6013 数据库更改
6014  
6015 
6016 SubmitChanges方法计算要插入、更 新或删除的已修改对象的集,并执行相应命令以实现对数据库的更改。
6017 
6018  
6019 
6020 无论对象做了多少项更改,都只是在更改内存中的副本。并未对数据库中的实际数据做任何更改。直到对DataContext显式调用SubmitChanges,所做的更改才会传输到服务器。调用时,DataContext会设法将我们所做的更改转换为等效的SQL 命令。我们也可以使用自己的自定义逻辑来重写这些操作,但提交顺序是由 DataContext的一项称作“更改处理器”的服务来协调的。事件的顺序如下:
6021 
6022  
6023 
6024 当调用SubmitChanges时,LINQ to SQL会检查已知对象的集合以确定新实例是否已附加到它们。如果已附加,这些新实例将添加到被跟踪对象的集合。
6025 
6026  
6027 
6028 所有具有挂起更改的对象将按照它们之间的依赖关系排序成一个对象序列。如果一个对象的更改依赖于其他对象,则这个对象将排在其依赖项之后。
6029 
6030  
6031 
6032 在即将传输任何实际更改时,LINQ to SQL会启动一个事务来封装由各条命令组成的系列。
6033 
6034  
6035 
6036 对对象的更改会逐个转换为SQL命令,然后发送到服务器。
6037 
6038  
6039 
6040 如果数据库检测到任何错误,都会造成提交进程停止并引发异常。将回滚对数据库的所有更改,就像未进行过提交一样。DataContext 仍具有所有更改的完整记录。
6041 
6042  
6043 
6044 下面代码说明的是在数据库中查询CustomerID 为ALFKI的顾客,然后修改其公司名称,第一次更新并调用SubmitChanges()方法,第二次更新了数据但并未调用SubmitChanges()方法。
6045 
6046 //查询
6047 
6048 Customer cust = db.Customers.First(c =>c.CustomerID == "ALFKI");
6049 
6050 //更新数据并调用SubmitChanges()方法
6051 
6052 cust.CompanyName = "YJingLee'sBlog";
6053 
6054 db.SubmitChanges();
6055 
6056 //更新数据没有调用SubmitChanges()方法
6057 
6058 cust.CompanyName ="http://lyj.cnblogs.com";
6059 
6060  
6061 
6062 动态查询
6063  
6064 
6065 使用动态查询,这个例子用CreateQuery()方法创建一个 IQueryable<T>类型表达式输出查询的语句。这里给个例子说明一下。有关动态查询具体内容,下一篇介绍。
6066 
6067  
6068 
6069 var c1 =Expression.Parameter(typeof(Customer), "c");
6070 
6071 PropertyInfo City =typeof(Customer).GetProperty ("City");
6072 
6073 var pred =Expression.Lambda<Func<Customer, bool>>(
6074 
6075    Expression.Equal(
6076 
6077   Expression.Property(c1, City),
6078 
6079    Expression.Constant("Seattle")
6080 
6081   ), c1
6082 
6083 );
6084 
6085 IQueryable custs = db.Customers;
6086 
6087 Expression expr =Expression.Call(typeof(Queryable), "Where",
6088 
6089   new Type[] { custs.ElementType }, custs.Expression, pred);
6090 
6091 IQueryable<Customer> q =db.Customers.AsQueryable().
6092 
6093 Provider.CreateQuery<Customer>(expr);
6094 
6095  
6096 
6097 日志
6098  
6099 
6100 Log属性用于将SQL查询或命令打印到TextReader。此方法对了解 LINQto SQL 功能和调试特定的问题可能很有用。
6101 
6102  
6103 
6104 下面的示例使用Log属性在 SQL代码执行前在控制台窗口中显示此代码。我们可以将此属性与查询、插入、更新和删除命令一起使用。
6105 
6106  
6107 
6108 //关闭日志功能
6109 
6110 //db.Log = null;
6111 
6112 //使用日志功能:日志输出到控制台窗口
6113 
6114 db.Log = Console.Out;
6115 
6116 var q = from c in db.Customers
6117 
6118     where c.City == "London"
6119 
6120     select c;
6121 
6122 //日志输出到 文件
6123 
6124 StreamWriter sw = newStreamWriter(Server.MapPath ("log.txt"), true);
6125 
6126 db.Log = sw;
6127 
6128 var q = from c in db.Customers
6129 
6130     where c.City == "London"
6131 
6132     select c;
6133 
6134 sw.Close();
6135 
6136  
6137 
6138 LINQ to SQL语句(23)之动态查询
6139 动态查询
6140 
6141  
6142 
6143 有这样一个场景:应用程序可能会提供一个用户界面,用户可以使用该用户界面指定一个或多个谓词来筛选数据。这种情况在编译时不知道查询的细节,动态查询将十分有用。
6144 
6145  
6146 
6147 在LINQ中,Lambda表达式是许多标准查询运算符的基础,编译器创建lambda表达式以捕获基础查询方法(例如 Where、Select、Order By、Take While 以及其他方法)中定义的计算。表达式目录树用于针对数据源的结构化查询,这些数据源实现IQueryable<T>。例如,LINQ to SQL 提供程序实现 IQueryable<T>接口,用于查询关系数据存储。C#和Visual Basic编译器会针对此类数据源的查询编译为代码,该代码在运行时将生成一个表达式目录树。然后,查询提供程序可以遍历表达式目录树数据结构,并将其转换为适合于数据源的查询语言。
6148 
6149  
6150 
6151 表达式目录树在 LINQ中用于表示分配给类型为Expression<TDelegate>的变量的Lambda表 达式。还可用于创建动态LINQ查询。
6152 
6153  
6154 
6155 System.Linq.Expressions命名空间 提供用于手动生成表达式目录树的API。Expression类包含创建特定类型的表达 式目录树节点的静态工厂方法,例如,ParameterExpression(表示一个已命名的参数表达式)或 MethodCallExpression(表示一个方法调用)。编译器生成的表达式目录树的根始终在类型Expression<TDelegate>的节点中,其中 TDelegate是包含至多五个输入参数的任何TDelegate委托;也就是说,其根节点是表示一个lambda表达式。
6156 
6157  
6158 
6159 下面几个例子描述如何使用表达式目录树来创建动态LINQ查询。
6160 
6161  
6162 
6163 1.Select
6164  
6165 
6166 下面例子说明如何使用表达式树依据 IQueryable 数据源构造一个动态查询,查询出每个顾客的ContactName,并用GetCommand方法获取其生成SQL语句。
6167 
6168  
6169 
6170 //依据IQueryable数据 源构造一个查询
6171 
6172 IQueryable<Customer> custs =db.Customers;
6173 
6174 //组建一个表达式树来创建一个参数
6175 
6176 ParameterExpression param =
6177 
6178   Expression.Parameter(typeof (Customer), "c");
6179 
6180 //组建表达式树:c.ContactName
6181 
6182 Expression selector =Expression.Property(param,
6183 
6184   typeof (Customer).GetProperty("ContactName"));
6185 
6186 Expression pred =Expression.Lambda(selector, param);
6187 
6188 //组建表达式树:Select(c=>c.ContactName)
6189 
6190 Expression expr = Expression.Call(typeof(Queryable), "Select",
6191 
6192   new Type[] { typeof (Customer), typeof(string) },
6193 
6194   Expression.Constant(custs), pred);
6195 
6196 //使用表达式树来生成动态查询
6197 
6198 IQueryable<string> query =db.Customers.AsQueryable()
6199 
6200   .Provider.CreateQuery<string>(expr);
6201 
6202 //使用GetCommand方法 获取SQL语句
6203 
6204 System.Data.Common.DbCommand cmd =db.GetCommand (query);
6205 
6206 Console.WriteLine(cmd.CommandText);
6207 
6208  
6209 
6210 生成的 SQL语句为:
6211 
6212  
6213 
6214 SELECT [t0].[ContactName] FROM [dbo]. [Customers]AS [t0]
6215 
6216 2.Where
6217  
6218 
6219 下面一个例子是“搭建”Where用法来动态查询城市在伦敦的顾客。
6220 
6221  
6222 
6223 IQueryable<Customer> custs =db.Customers;
6224 
6225 // 创建一个参数c
6226 
6227 ParameterExpression param =
6228 
6229    Expression.Parameter(typeof(Customer), "c");
6230 
6231 //c.City=="London"
6232 
6233 Expression left = Expression.Property(param,
6234 
6235   typeof(Customer).GetProperty ("City"));
6236 
6237 Expression right = Expression.Constant("London");
6238 
6239 Expression filter = Expression.Equal(left,right);
6240 
6241 Expression pred = Expression.Lambda(filter,param);
6242 
6243 //Where(c=>c.City=="London")
6244 
6245 Expression expr = Expression.Call(typeof(Queryable),"Where",
6246 
6247   new Type[] { typeof(Customer) },
6248 
6249   Expression.Constant(custs), pred);
6250 
6251 //生成动态查询
6252 
6253 IQueryable<Customer> query =db.Customers.AsQueryable()
6254 
6255   .Provider.CreateQuery<Customer>(expr);
6256 
6257  
6258 
6259 生成的SQL 语句为:
6260 
6261  
6262 
6263 SELECT [t0].[CustomerID],[t0].[CompanyName], [t0].[ContactName],
6264 
6265 [t0].[ContactTitle], [t0].[Address], [t0].[City], [t0].[Region],
6266 
6267 [t0].[PostalCode], [t0].[Country], [t0].[Phone], [t0].[Fax]
6268 
6269 FROM [dbo].[Customers] AS [t0] WHERE [t0].[City] = @p0
6270 
6271 -- @p0: Input NVarChar (Size = 6; Prec = 0;Scale = 0) [London]
6272 
6273  
6274 
6275 3.OrderBy本例既实现排序功能又实现了过滤功能。
6276 
6277  
6278 
6279 IQueryable<Customer> custs =db.Customers;
6280 
6281 //创建一个 参数c
6282 
6283 ParameterExpression param =
6284 
6285   Expression.Parameter (typeof(Customer), "c");
6286 
6287 //c.City=="London"
6288 
6289 Expression left = Expression.Property(param,
6290 
6291    typeof(Customer).GetProperty ("City"));
6292 
6293 Expression right = Expression.Constant("London");
6294 
6295 Expression filter = Expression.Equal(left,right);
6296 
6297 Expression pred = Expression.Lambda(filter,param);
6298 
6299 //Where(c=>c.City=="London")
6300 
6301 MethodCallExpression whereCallExpression =Expression.Call(
6302 
6303    typeof(Queryable), "Where",
6304 
6305    new Type[] { typeof(Customer) },
6306 
6307    Expression.Constant(custs), pred);
6308 
6309 //OrderBy(ContactName => ContactName)
6310 
6311 MethodCallExpression orderByCallExpression= Expression.Call(
6312 
6313    typeof(Queryable), "OrderBy",
6314 
6315    new Type[] { typeof(Customer), typeof(string) },
6316 
6317    whereCallExpression,
6318 
6319    Expression.Lambda(Expression.Property
6320 
6321    (param, "ContactName"), param));
6322 
6323 //生成动态查询
6324 
6325 IQueryable<Customer> query =db.Customers.AsQueryable()
6326 
6327    .Provider.CreateQuery<Customer> (orderByCallExpression);
6328 
6329  
6330 
6331 下面一张截图显示了怎么动态生成动态查询的过程
6332 
6333  
6334 
6335 生成的SQL语句为:
6336 
6337  
6338 
6339 SELECT [t0].[CustomerID],[t0].[CompanyName], [t0].[ContactName],
6340 
6341 [t0].[ContactTitle], [t0].[Address],[t0].[City], [t0].[Region],
6342 
6343 [t0].[PostalCode], [t0].[Country], [t0].[Phone],[t0].[Fax]
6344 
6345 FROM [dbo].[Customers] AS [t0] WHERE[t0].[City] = @p0
6346 
6347 ORDER BY [t0].[ContactName]
6348 
6349 -- @p0: Input NVarChar (Size = 6; Prec = 0;Scale = 0) [London]
6350 
6351 4.Union
6352 
6353  
6354 
6355 下面的例子使用表达式树动态查询顾客和雇员同在的城市。
6356 
6357  
6358 
6359 //e.City
6360 
6361 IQueryable<Customer> custs = db.Customers;     
6362 
6363 ParameterExpression param1 =
6364 
6365 Expression.Parameter(typeof(Customer),"e");
6366 
6367 Expression left1 =Expression.Property(param1,
6368 
6369   typeof (Customer).GetProperty("City"));
6370 
6371 Expression pred1 = Expression.Lambda(left1,param1);
6372 
6373 //c.City
6374 
6375 IQueryable<Employee> employees =db.Employees;
6376 
6377 ParameterExpression param2 =
6378 
6379 Expression.Parameter(typeof (Employee),"c");
6380 
6381 Expression left2 =Expression.Property(param2,
6382 
6383   typeof(Employee).GetProperty ("City"));
6384 
6385 Expression pred2 = Expression.Lambda(left2,param2);
6386 
6387 //Select(e=>e.City)
6388 
6389 Expression expr1 =Expression.Call(typeof(Queryable), "Select",
6390 
6391   new Type[] { typeof(Customer), typeof(string) },
6392 
6393    Expression.Constant(custs), pred1);
6394 
6395 //Select(c=>c.City)
6396 
6397 Expression expr2 =Expression.Call(typeof(Queryable), "Select",
6398 
6399   new Type[] { typeof(Employee), typeof (string) },
6400 
6401   Expression.Constant(employees), pred2);
6402 
6403 //生 成动态查询
6404 
6405 IQueryable<string> q1 =db.Customers.AsQueryable()
6406 
6407   .Provider.CreateQuery<string>(expr1);
6408 
6409 IQueryable<string> q2 =db.Employees.AsQueryable()
6410 
6411   .Provider.CreateQuery<string>(expr2);
6412 
6413 //并集
6414 
6415 var q3 = q1.Union(q2);
6416 
6417  
6418 
6419 生成的SQL语句为:
6420 
6421  
6422 
6423 SELECT [t2].[City]
6424 
6425 FROM (
6426 
6427   SELECT [t0].[City] FROM [dbo]. [Customers] AS [t0]
6428 
6429   UNION
6430 
6431   SELECT [t1].[City] FROM [dbo].[Employees] AS [t1]
6432 
6433   ) AS [t2]
6434 
6435  
6436 
6437 LINQ to SQL语句(24)之视图
6438 视图
6439 
6440  
6441 
6442 我们使用视图和使用数据表类似,只需将视图从“服务器资源管理器/数据库资源管理器”拖动到O/R 设计器上,自动可以创建基于这些视图的实体类。我们可以同操作数据表一样来操作视图了。这里注意:O/R 设计器是一个简单的对象关系映射器,因为它仅支持 1:1 映射关系。换句话说,实体类与数据库表或视图之间只能具有 1:1 映射关系。不支持复杂映射(例如,将一个实体类映射到多个表)。但是,可以将一个实体类映射到一个联接多个相关表的视图。 下面使用NORTHWND数据库中自带的Invoices、QuarterlyOrders  两个视图为例,写出两个范例。
6443 
6444  
6445 
6446 查询:匿名类型形式
6447 
6448  
6449 
6450 我们使用下面代码来查询出ShipCity 在London的发票。
6451 
6452  
6453 
6454 var q =
6455 
6456   from i in db.Invoices
6457 
6458   where i.ShipCity == "London"
6459 
6460   select new
6461 
6462   {
6463 
6464     i.OrderID,
6465 
6466      i.ProductName,
6467 
6468     i.Quantity,
6469 
6470     i.CustomerName
6471 
6472   };
6473 
6474  
6475 
6476 这里,生成的SQL语句同使用数据表类似:
6477 
6478  
6479 
6480 SELECT [t0].[OrderID], [t0].[ProductName],[t0]. [Quantity],
6481 
6482 [t0].[CustomerName] FROM [dbo].[Invoices]AS [t0]
6483 
6484 WHERE [t0].[ShipCity] = @p0
6485 
6486 -- @p0: Input NVarChar (Size = 6; Prec = 0;Scale = 0) [London]
6487 
6488 查询:标识映射形式
6489 
6490  
6491 
6492 下例查询出每季的订单。
6493 
6494  
6495 
6496 var q =
6497 
6498   from qo in db.Quarterly_Orders
6499 
6500   select qo;
6501 
6502  
6503 
6504 生成SQL语句为:
6505 
6506  
6507 
6508 SELECT [t0].[CustomerID],[t0].[CompanyName], [t0]. [City],
6509 
6510 [t0].[Country] FROM [dbo].[QuarterlyOrders] AS [t0]
6511 
6512  
6513 
6514 LINQ to SQL语句(25)之继承
6515 继承支持
6516 
6517  
6518 
6519 LINQ to SQL 支持单表映射,其整个继承层次结构存储在单个数据库表中。该表包含整个层次结构的所有可能数据列的平展联合。(联合是将两个表组合成一个表的结果,组合后的表包含任一原始表中存在的行。)每行中不适用于该行所表示的实例类型的列为 null6520 
6521  
6522 
6523 单表映射策略是最简单的继承表示形式,为许多不同类别的查询提供了良好的性能特征,如果我们要在 LINQ to SQL 中实现这种映射,必须在继承层次结构的根类中指定属性 (Attribute) 和属性 (Attribute) 的属性 (Property)。我们还可以使用O/R设计器来映射继承层次结构,它自动生成了代码。
6524 
6525  
6526 
6527 下面为了演示下面的几个例子,我们在O/R设计器内设计如下图所示的类及其继承关系。
6528 
6529  
6530 
6531 我们学习的时候还是看看其生成的代码吧!
6532 
6533  
6534 
6535 具体设置映射继承层次结构有如下几步:
6536 
6537  
6538 
6539 根类添加TableAttribute属性。
6540 
6541  
6542 
6543 为层次结构中的每个类添加InheritanceMappingAttribute属性,同样是添加到根类中。每个InheritanceMappingAttribute属性,定义一个Code属性和一个Type属性。Code 属性的值显示在数据库表的IsDiscriminator列中,用来指示该行数据所属的类或子类。Type属性值指定键值所表示的类或子类。
6544 
6545  
6546 
6547 仅在其中一个 InheritanceMappingAttribute属性上,添加一个IsDefault属性用来在数据库表 中的鉴别器值在继承映射中不与任何Code值匹配时指定回退映射。
6548 
6549  
6550 
6551 为 ColumnAttribute属性添加一个IsDiscriminator属性来表示这是保存Code值的列。
6552 
6553  
6554 
6555 下面是这张图生成的代码的框架(由于生成的代码太多,我删除了很多“枝叶”,仅仅保留了主要的框架用于指出其实质的东西):
6556 
6557  
6558 
6559 [Table(Name = "dbo.Contacts")]
6560 
6561 [InheritanceMapping(Code ="Unknown", Type = typeof (Contact),
6562 
6563           IsDefault = true)]
6564 
6565 [InheritanceMapping(Code ="Employee", Type = typeof (EmployeeContact))]
6566 
6567 [InheritanceMapping(Code ="Supplier", Type = typeof(SupplierContact))]
6568 
6569 [InheritanceMapping(Code ="Customer", Type = typeof (CustomerContact))]
6570 
6571 [InheritanceMapping(Code ="Shipper", Type = typeof(ShipperContact))]
6572 
6573 public partial class Contact :
6574 
6575 INotifyPropertyChanging,INotifyPropertyChanged
6576 
6577 {
6578 
6579   [Column(Storage = "_ContactID",IsPrimaryKey = true,
6580 
6581   IsDbGenerated = true)]
6582 
6583   public int ContactID{ }
6584 
6585   [Column(Storage = "_ContactType",IsDiscriminator = true)]
6586 
6587   public string ContactType{ }
6588 
6589 }
6590 
6591 public abstract partial class FullContact :Contact{ }
6592 
6593 public partial class EmployeeContact :FullContact{ }
6594 
6595 public partial class SupplierContact :FullContact{ }
6596 
6597 public partial class CustomerContact :FullContact{ }
6598 
6599 public partial class ShipperContact :Contact{ }
6600 
6601  
6602 
6603 1.一般形式
6604  
6605 
6606 日常我们经常写的形式,对单表查询。
6607 
6608  
6609 
6610 var cons = from c in db.Contacts
6611 
6612       select c;
6613 
6614 foreach (var con in cons) {
6615 
6616    Console.WriteLine("Company name: {0}", con.CompanyName);
6617 
6618   Console.WriteLine("Phone: {0}", con.Phone);
6619 
6620    Console.WriteLine("This is a {0}", con.GetType());
6621 
6622 }
6623 
6624  
6625 
6626 2.OfType形式
6627  
6628 
6629 这里我仅仅让其返回顾客的联系方式。
6630 
6631  
6632 
6633 var cons = from c indb.Contacts.OfType<CustomerContact>()
6634 
6635       select c;
6636 
6637  
6638 
6639 初步学习,我们还是看看生成的SQL语句,这样容易理解。在 SQL语句中查询了ContactType为Customer的联系方式。
6640 
6641  
6642 
6643 SELECT [t0].[ContactType],[t0].[ContactName], [t0].[ContactTitle],
6644 
6645 [t0].[Address],[t0].[City], [t0].[Region],[t0].[PostalCode],
6646 
6647 [t0].[Country],[t0].[Fax],[t0].[ContactID], [t0].[CompanyName],
6648 
6649 [t0].[Phone] FROM [dbo].[Contacts] AS [t0]
6650 
6651 WHERE ([t0]. [ContactType] = @p0) AND([t0].[ContactType] IS NOT NULL)
6652 
6653 -- @p0: Input NVarChar (Size = 8; Prec = 0;Scale = 0) [Customer]
6654 
6655  
6656 
6657 3.IS形式
6658  
6659 
6660 这个例子查找一下发货人的联系方式。
6661 
6662  
6663 
6664 var cons = from c in db.Contacts
6665 
6666       where c is ShipperContact
6667 
6668       select c;
6669 
6670  
6671 
6672 生成的SQL语句如下:查询了ContactType为Shipper的联系方式。大致一看好像很上面的一样,其实这里查询出来的列多了很多。实际上是Contacts表的全部字段。
6673 
6674  
6675 
6676 SELECT [t0].[ContactType],[t0].[ContactID], [t0]. [CompanyName],
6677 
6678 [t0].[Phone],[t0].[HomePage], [t0].[ContactName],
6679 
6680 [t0].[ContactTitle], [t0].[Address], [t0].[City],
6681 
6682 [t0].[Region], [t0].[PostalCode],[t0].[Country],
6683 
6684 [t0].[Fax],[t0].[PhotoPath], [t0].[Photo],[t0].[Extension]
6685 
6686 FROM [dbo].[Contacts] AS [t0] WHERE([t0].[ContactType] = @p0)
6687 
6688 AND ([t0].[ContactType] IS NOT NULL)
6689 
6690 -- @p0: Input NVarChar (Size = 7; Prec = 0;Scale = 0) [Shipper]
6691 
6692  
6693 
6694 4.AS形式
6695  
6696 
6697 这个例子就通吃了,全部查找了一番。
6698 
6699  
6700 
6701 var cons = from c in db.Contacts
6702 
6703       select c as FullContact;
6704 
6705  
6706 
6707 生成 SQL语句如下:查询整个Contacts表。
6708 
6709  
6710 
6711 SELECT [t0]. [ContactType],[t0].[HomePage], [t0].[ContactName],
6712 
6713 [t0]. [ContactTitle],[t0].[Address],[t0].[City],
6714 
6715 [t0].[Region], [t0]. [PostalCode],[t0].[Country],
6716 
6717 [t0].[Fax], [t0].[ContactID],[t0].[CompanyName],
6718 
6719 [t0].[Phone],[t0].[PhotoPath],[t0].[Photo], [t0].[Extension]
6720 
6721 FROM [dbo].[Contacts] AS [t0]
6722 
6723  
6724 
6725 5.Cast形式
6726  
6727 
6728 使用Case形式查找出在伦敦的顾客的联系方式。
6729 
6730  
6731 
6732 var cons = from c in db.Contacts
6733 
6734       where c.ContactType == "Customer" &&
6735 
6736            ((CustomerContact)c).City == "London"
6737 
6738       select c;
6739 
6740  
6741 
6742 生成SQL语句如下,自己可以看懂了。
6743 
6744  
6745 
6746 SELECT [t0].[ContactType],[t0].[ContactID], [t0]. [CompanyName],
6747 
6748 [t0].[Phone], [t0].[HomePage],[t0].[ContactName],
6749 
6750 [t0].[ContactTitle], [t0].[Address],[t0].[City], [t0].[Region],
6751 
6752 [t0].[PostalCode], [t0].[Country],[t0].[Fax], [t0].[PhotoPath],
6753 
6754 [t0].[Photo], [t0].[Extension]FROM [dbo].[Contacts] AS [t0]
6755 
6756 WHERE ([t0].[ContactType] = @p0) AND ([t0].[City] = @p1)
6757 
6758 -- @p0: Input NVarChar (Size = 8; Prec = 0;Scale = 0) [Customer]
6759 
6760 -- @p1: Input NVarChar (Size = 6; Prec = 0;Scale = 0) [London]
6761 
6762  
6763 
6764 6.UseAsDefault形式
6765  
6766 
6767 当插入一条记录时,使用默认的映射关系了,但是在查询时,使用继承的关系了。具体看看生成的SQL 语句就直截了当了。
6768 
6769  
6770 
6771 //插入一条数据默认使用正常的映射关系
6772 
6773 Contact contact = new Contact()
6774 
6775 {
6776 
6777   ContactType = null,
6778 
6779   CompanyName = "Unknown Company",
6780 
6781    Phone = "333-444-5555"
6782 
6783 };
6784 
6785 db.Contacts.InsertOnSubmit(contact);
6786 
6787 db.SubmitChanges();
6788 
6789 //查询一条数据默认使用继承映射关系
6790 
6791 var con =
6792 
6793   (from c in db.Contacts
6794 
6795    where c.CompanyName == "Unknown Company" &&
6796 
6797               c.Phone == "333-444-5555"
6798 
6799    select c).First();
6800 
6801  
6802 
6803 生成SQL语句如下:
6804 
6805  
6806 
6807 INSERT INTO [dbo].[Contacts]([ContactType], [CompanyName],
6808 
6809 [Phone]) VALUES (@p0, @p1, @p2)
6810 
6811 SELECT TOP (1) [t0].[ContactType], [t0].[ContactID],
6812 
6813 [t0]. [CompanyName],[t0].[Phone],[t0].[HomePage],
6814 
6815 [t0].[ContactName], [t0].[ContactTitle],[t0].[Address],
6816 
6817 [t0].[City],[t0].[Region],[t0].[PostalCode], [t0].[Country],
6818 
6819 [t0].[Fax], [t0].[PhotoPath], [t0].[Photo],[t0].[Extension]
6820 
6821 FROM [dbo].[Contacts] AS [t0]
6822 
6823 WHERE ([t0].[CompanyName] = @p0) AND([t0].[Phone] = @p1)
6824 
6825 -- @p0: Input NVarChar (Size = 15; Prec =0; Scale = 0)
6826 
6827   [Unknown Company]
6828 
6829 -- @p1: Input NVarChar (Size = 12; Prec =0; Scale = 0)
6830 
6831   [333-444-5555]
6832 
6833  
6834 
6835 7.插入新的记录
6836  
6837 
6838 这个例子说明如何插入发货人的联系方式的一条记录。
6839 
6840  
6841 
6842 //
6843 
6844  
6845 
6846 1.在插入之前查询一下,没有数据
6847 var ShipperContacts =
6848 
6849   from sc in db.Contacts.OfType<ShipperContact>()
6850 
6851   where sc.CompanyName == "Northwind Shipper"
6852 
6853   select sc;
6854 
6855 //
6856 
6857  
6858 
6859 2.插入数据
6860 ShipperContact nsc = new ShipperContact()
6861 
6862 {
6863 
6864   CompanyName = "Northwind Shipper",
6865 
6866   Phone = "(123)-456-7890"
6867 
6868 };
6869 
6870 db.Contacts.InsertOnSubmit(nsc);
6871 
6872 db.SubmitChanges();
6873 
6874 //
6875 
6876  
6877 
6878 3.查询数据,有一条记录
6879 ShipperContacts =
6880 
6881   from sc in db.Contacts.OfType<ShipperContact>()
6882 
6883    where sc.CompanyName == "Northwind Shipper"
6884 
6885   select sc;
6886 
6887 //
6888 
6889  
6890 
6891 4.删除记录
6892 db.Contacts.DeleteOnSubmit (nsc);
6893 
6894 db.SubmitChanges();
6895 
6896  
6897 
6898 生成SQL语句如下:
6899 
6900  
6901 
6902 SELECT COUNT(*) AS [value] FROM[dbo].[Contacts] AS [t0]
6903 
6904 WHERE ([t0].[CompanyName] = @p0) AND([t0].[ContactType] = @p1)
6905 
6906 AND ([t0].[ContactType] IS NOT NULL)
6907 
6908 -- @p0: Input NVarChar [Northwind Shipper]
6909 
6910 -- @p1: Input NVarChar [Shipper]
6911 
6912 INSERT INTO [dbo].[Contacts]([ContactType],[CompanyName], [Phone])
6913 
6914 VALUES (@p0, @p1, @p2)
6915 
6916 -- @p0: Input NVarChar [Shipper]
6917 
6918 -- @p1: Input NVarChar [NorthwindShipper]
6919 
6920 -- @p2: Input NVarChar [(123)-456-7890]
6921 
6922 SELECT COUNT(*) AS [value] FROM[dbo].[Contacts] AS [t0]
6923 
6924 WHERE ([t0].[CompanyName] = @p0) AND([t0].[ContactType] = @p1)
6925 
6926 AND ([t0].[ContactType] IS NOT NULL)
6927 
6928 -- @p0: Input NVarChar [Northwind Shipper]
6929 
6930 -- @p1: Input NVarChar [Shipper]
6931 
6932 DELETE FROM [dbo].[Contacts] WHERE ([ContactID]= @p0) AND
6933 
6934 ([ContactType] = @p1) AND ([CompanyName] =@p2) AND ([Phone] = @p3)
6935 
6936 -- @p0: Input Int [159]
6937 
6938 -- @p1: Input NVarChar [Shipper]
6939 
6940 -- @p2: Input NVarChar [NorthwindShipper]
6941 
6942 -- @p3: Input NVarChar [(123)-456-7890]
6943 
6944 -- @p4: Input NVarChar [Unknown]
6945 
6946 -- @p5: Input NVarChar (Size = 8; Prec = 0;Scale = 0) [Supplier]
6947 
6948 -- @p6: Input NVarChar (Size = 7; Prec = 0;Scale = 0) [Shipper]
6949 
6950 -- @p7: Input NVarChar (Size = 8; Prec = 0;Scale = 0) [Employee]
6951 
6952 -- @p8: Input NVarChar (Size = 8; Prec = 0;Scale = 0) [Customer]

 

posted @ 2018-10-17 17:17  Hao0  阅读(550)  评论(0编辑  收藏  举报