一步一步學Entity Framework 4.x (3)


本系列教程發上去以后,有的朋友問我為什么不用Code First呢?個人認為,各種方法各有千秋,而且不管用哪種模式,最后達到的效果是一樣的,實質上使用的基本方法是相通的,這就足夠了.況且前面已經全文翻譯了一本書,如果重復這本書的內容,就沒多大意思了,毫無疑問,本文對於Code First模式的學習也是有指導作用的,理解了基本的機制,再進行其他方面深入知識的掌握就容易了,不是嗎?我在這里寫的內容都是通過不斷的實踐摸索總結出來的,可以說是很基礎的東西,並不是想要炫耀什么,只是因為前面自已走的彎路太多,不想讓像我這種剛入門的人再重復一些不必要的彎路而已...

書歸正傳,接上期博客文章,繼續將數據查詢的問題學習完畢.

5)單值選擇查詢:

在SQL數據查詢里,經常會用到SELECT DISTINCT查詢,用來搜索數據中的唯一值,注意不是第一個,而是重復數據中的一個.

比如想要查詢Product表中ProductUnit(單位)的個數,就會用到單值選擇查詢.Linq提供了Distinct擴展方法,解決這一問題,如此例,代碼應為:

 var result = from c in ctx.Product
                           select c.ProductUnitId;
              return result.Distinct().Count();

而使用方法語法則應為:

return ctx.Product.Select(c => c.ProductUnitId).Distinct().Count();

6)多級排序:

比如按照ProductName排序完成后,還要按ProductUnitName再次進行逆序排序,最后再按ProductBigTypeName來排序,這需要使用下面的查詢語法代碼(接前述GetProductDepositoryByPrice方法里的代碼):

var result = from c in ctx.Product
                           join d in ctx.ProductSmallType on c.ProductSmallTypeId equals d.ProductSmallTypeId
                           join e in ctx.ProductBigType on d.ProductBigTypeId equals e.ProductBigTypeId
                           join f in ctx.ProductUnit on c.ProductUnitId equals f.ProductUnitId
                           where c.ProductBasePrice<=50 && c.ProductBasePrice >=49

                           orderby c.ProductName,f.ProductUnitName descending,e.ProductBigTypeName
                           select new ProductDepository
                           {
                               ProductName = c.ProductName,
                               ProductBigTypeName = e.ProductBigTypeName,
                               ProductSmallTypeName = d.ProductSmallTypeName,
                               ProductUntName = f.ProductUnitName

                           };
              return result.ToList();

使用方法語法(按前述GetProductByPrice方法里的代碼),則應寫作:

return ctx.Product.Include("ProductUnit").
                  Include("ProductSmallType").Include("ProductSmallType.ProductBigType")
                  .Where(c => (c.ProductBasePrice <= 50 && c.ProductBasePrice >= 49))
                  .OrderBy(c=>c.ProductName )
                  .ThenByDescending(c=>c.ProductUnit.ProductUnitName)
                  .ThenBy(c=>c.ProductSmallType.ProductBigType.ProductBigTypeName)
                  .ToList();

7)Top 10的實現

只選擇前幾條數據可以使用Take方法,比如Take(10)就表示取結果的前10條.可以直接在方法語法后面加上這個擴展方法,各位園友請自行試驗,在此不再舉例.

8)實現快速分頁的關鍵方法:Skip方法,這一方法可以跳過指定的記錄條數,返回剩余的記錄,這可以應用於快速分頁,因為跳過的記錄不會進入內存,也不會占用服務器資源,這樣就可以直接顯示指定頁面的數據了,Skip方法和Take方法協同使用,可以只調用所需要的當前頁面數據,大大縮小的查詢數據的區間,分頁效率最高.這一方法使用比較簡單,就不再舉例.

9)返回結果中第一個匹配給定條件的數據,應該使用First或FirstOrDefault方法,在給定條件有數據返回時.兩個方法類似,當給定條件無數據返回時,First方法返回Null,而FirstOrDefault方法返回為默認元素(如果是字符串,返回為"",如果是數字,返回0等等),所以注意對返回結果的處理,特別是對First方法返回值的處理,不要出現引用Null值的錯誤,否則會引發異常.通常的做法是在使用前對返回值是否為Null進行判斷,要么就使用FirstOrDefault方法.

前面介紹了大部分常用的查詢功能,有了這些查詢方法,就可以在實際工作中施展拳腳了,大家多嘗試多練習,就會體會到Linq查詢的妙處.

6、刪除數據

刪除數據有兩種情況,一種是對一對多關系中的“多”進行刪除,這很容易,直接刪除就是,比如Produc表;另一種是對一對多關系中的“一”進行刪除,如果沒有設置級聯刪除,將無法直接刪除,除非已經將符合條件的“多”的部分全部刪除了,才能正常刪除與“多”相關的“一”,個人建議開啟級聯刪除功能,這樣在實際開發工作中事半功倍,否則在實際運行中出現刪除不了的錯誤,也不好進行調試。在SQL Server Management Stuido里可以很容易地實現級聯刪除功能,見下圖:

imageimage

級聯設置完成后,就可以方便地進行刪除操作了。這時候,我們就不用再顧慮是否能夠正確刪除的問題了,只要查詢到了數據,就可以刪除。

想要刪除數據,首先要找到數據,這就要用到前面所學的查詢語句及工具了。

在刪除數據時要注意,如果查詢得到的是單條數據,例如使用First或FirstOrDefault方法獲取的數據,直接調用實體類的DeleteObject方法就可以了,然后再調用SaveChanges方法將所有更改進行更新。但是如果查詢得到的是數據集合,就不能像SQL語句那樣對數據進行批量刪除操作了,這時需要使用foreach循環語句遍歷所有數據,逐個調用DeleteObject方法。最后統一調用SaveChanges方法即可(從SaveChanges方法名就可以看到,這個方法是可以批量處理數據的)。

 

比如想要刪除ProductSmallType表中ProductBigTypeName(需要導航得到,原表中沒有這個屬性)以9結尾的所有數據,方法如下:

1)首先在Business文件夾中新建一個類,命名為DeleteData.cs;

2)在類中添加一個方法DeleteProductSmallTypeByBigTypeName(),代碼如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ProductEFDemo.Models;

namespace ProductEFDemo.Business
{
  public static  class DeleteData
    {
      public static void DeleteProductSmallTypeByBigTypeName()
      {
          using (var ctx = new ProductsEntities())
          {
              var result = ctx.ProductSmallType.Include("ProductBigType")
                         .Where(c => c.ProductBigType.ProductBigTypeName.EndsWith("9"))
                         .ToList();
              foreach (var productSmallType in result)
              {
                  ctx.ProductSmallType.DeleteObject(productSmallType);
              }
              ctx.SaveChanges();
          }
      }
    }
}

3)在Presenter文件夾中,添加一個類:DeleteObjectView.cs

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ProductEFDemo.Business;

namespace ProductEFDemo.Presenter
{
  public static  class DeleteObjectView
    {
      public static void DeleteProductSmallTypeByBigTypeName()
      {
          Console.WriteLine("真的要全部刪除?");
          string str = Console.ReadLine();
          if (str.Substring(0, 1).ToLower() == "y")
          {
              try
              {
                  DeleteData.DeleteProductSmallTypeByBigTypeName();
                  Console.WriteLine("成功刪除所有相關數據及相關關聯數據");
              }
              catch (Exception ex)
              {

                  Console.WriteLine(String.Format ("出錯,錯誤信息為:{0}",ex.Message));
              }
           

          }
          
      }
    }
}

4)在Programm.cs中的Main函數調用這一方法,結果如下:

image

再到數據庫的ProductSmallType表里去找相關數據,已經沒有了,記錄已經變成了90條,到Product表里去找相關數據,記錄變成了9000條,有1000條數據也被同時刪除了,盡管我們並沒有顯示地指定要刪除這些數據,但是由於設置了級聯,就將一對多中的多的部分也刪除了。

當然了,這種刪除是對數據的永久性刪除,一般來說不是一個很好的模式,萬一想反悔已經來不及了。所以大型項目通常都是設置一個數據列,標記被刪除的那一行數據為已刪除(實際上數據還在,只是不在前台里顯示了而已),這需要使用更新語句,而不是真正的刪除語句,然后以后在確定不會后悔了以后再真的將數據清空,建議園友們在實際項目中也這樣操作,算是一味后悔葯吧!

 

7、更新和修改數據

這是本系列的最后一部分,實現了添加,查找,刪除,下面就該實現數據的修改了。數據修改的方法與數據刪除的方法相類似,也是先要通過Linq查詢到數據,然后給查詢到數據對象的相關屬性進行賦值修改,最后再調用SaveChanges方法更新就OK了。

同樣,對於集合類數據的修改,也不能一並進行更新處理,只能通過循環對各個對象逐個進行更新處理。這一點一定要注意!

下面對ProductUnit表中的ProductName進行修改,將所有“測試”字符串替換為””,步驟如下:

1)首先還是在Business文件夾中添加一個類:UpdateData.cs:

2)然后在類中添加一個方法實現前面要實現的更新功能:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ProductEFDemo.Models;

namespace ProductEFDemo.Business
{
  public static  class UpdateData
    {
      public static void UpdateProductUnitByUnitName()
      {
          using (var ctx = new ProductsEntities())
          {
              var result = ctx.ProductUnit.Where(c => c.ProductUnitName.Contains("測試")).ToList();
              foreach (var productUnit in result)
              {
                  productUnit.ProductUnitName = productUnit.ProductUnitName.Replace("測試", "");
              }
              ctx.SaveChanges();
          }
      }
    }
}

 

3)在Presenter文件夾中添加一個類:UpdateDateView.cs。

4)在類中實現一個方法調用剛剛創建的方法:

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ProductEFDemo.Business;

namespace ProductEFDemo.Presenter
{
  public static class UpdateDateView
    {
      public static void UpdateProductUnitByUnitName()
      {
         try
         {
             Console.WriteLine("准備更新數據...");
             UpdateData.UpdateProductUnitByUnitName();
             Console.WriteLine("更新成功!");
         }
         catch (System.Exception ex)
         {
             Console.WriteLine(String.Format("出錯,錯誤信息為:{0}", ex.Message));
         }
         
      }
    }
}

5)執行程序,結果如下:

image

到數據庫中檢索數據,

image

可見數據都進行了更新和修改。是不是很方便?

總結一下,想怎樣改數據都是在實體類的對象上改,對象改完以后直接SaveChanges就OK了,很簡單很方便!

 

8、小結:Entity Framework還有很多高級知識,如延遲加載(Lazy Load),數據庫自定義加載,並發處置等,這些還需要進一步研究和討論,但是掌握了基礎知識以后,這些新的知識就可以獲得更好的理解了,希望園友們再接再厲,深入研究EF這一ORM工具,大幅度地提高生產力!

 

聲明:本文系本人原創,版權歸屬作者和博客園共同所有,任何組織或個人不得隨意轉載,修改。需要轉載請與本人聯系:qouoww@163.com。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM