接上一篇文章。現(xiàn)在寫程序,做項(xiàng)目不是說(shuō)功能做完就完事了,在平常的開發(fā)過(guò)程中對(duì)于性能的考慮也是極其重要的。

          關(guān)于ef的那些事,今天就來(lái)說(shuō)說(shuō)吧。首先必須得知道.net ef在程序中的五種狀態(tài)變化過(guò)程與原理。


          主要來(lái)說(shuō)說(shuō)查詢部分的性能優(yōu)化,在所有查詢中,客戶端查詢出來(lái)的數(shù)據(jù)一般來(lái)說(shuō)是不需要進(jìn)行跟蹤的。也就是說(shuō)查詢只是給用戶看,不做其他任何操作。對(duì)于基于B/S模式的項(xiàng)目網(wǎng)站開發(fā),應(yīng)該是無(wú)狀態(tài)的,也就是ef中的游離態(tài)(Unchanged)(個(gè)人理解)。如果是C/S可能還需要進(jìn)行其他連接的狀態(tài)。通俗的說(shuō),在開發(fā)過(guò)程不用去檢測(cè)某一個(gè)屬性或者類是否被修改或者刪除。

          例如:

          AsNoTracking:它的作用就是在查詢的過(guò)程中不被緩存,也就是不被保留,查出來(lái)就完事了,這樣的狀態(tài)就變成了Detached游離態(tài)
          //AsNoTracking:它的性能比ToList快大約4.8倍,不被緩存的數(shù)據(jù)。 var
          item=db.Book.AsNoTracking().First(m=>m.Id==1);
          Console.WriteLine(db.Entry(item).State);//輸出Detached(游離態(tài))
          去掉AsNoTracking
          var item=db.Book.First(m=>m.Id==1); Console.WriteLine(db.Entry(item).State); //
          輸出UnChanged(持久態(tài))
          也就是加上AsNoTracking做出來(lái)的查詢操作,就和數(shù)據(jù)庫(kù)斷絕了關(guān)系(個(gè)人理解)這樣對(duì)性能也是一個(gè)極好的優(yōu)化。

          然后來(lái)說(shuō)說(shuō)在項(xiàng)目中對(duì)ef整體框架優(yōu)化的使用。


          C#是一門面向?qū)ο蟮恼Z(yǔ)言無(wú)外乎就是封裝、繼承、多態(tài)。。。類可以繼承類,同樣接口也可以繼承接口。面向?qū)ο蟮乃枷刖褪敲繌埍矶紤?yīng)該有一個(gè)父類,只寫一遍,其他類繼承就好了不用重復(fù)去寫。

          建立一個(gè)空白的解決方案,添加一個(gè)名為BaseEntity的類,你可以把它看做是所有類的基礎(chǔ)類(父類)。



          重點(diǎn)來(lái)說(shuō)說(shuō)這個(gè)BaseEntity為什么要作為基礎(chǔ)類,它的用意何在。

          先看看里面的寫了些什么吧!

          以前用int或者long作為主鍵自增長(zhǎng)的數(shù)據(jù)類型,這樣后期數(shù)據(jù)非常龐大的時(shí)候可能會(huì)無(wú)法預(yù)估難免可能會(huì)出現(xiàn)重復(fù)的數(shù)據(jù),這個(gè)時(shí)候?qū)τ谡麄€(gè)系統(tǒng)來(lái)說(shuō)就無(wú)法保障了。

          Guid給我做出了一個(gè)計(jì)算,它是32位的數(shù)字加字母的組合,而且是特別長(zhǎng)的不會(huì)重復(fù)的自增數(shù),可以這樣去理解。


          DateTime就是每條數(shù)據(jù)的創(chuàng)建時(shí)間,IsRemove就是作為數(shù)據(jù)邏輯刪除的標(biāo)識(shí),也就是說(shuō),每個(gè)類(表)都會(huì)存在這三個(gè)字段屬性。你可以通過(guò)DateTime對(duì)沒(méi)張表進(jìn)行排序的操作。
          using System; namespace Book.Models { public class BaseEntity { public Guid Id
          {get; set; }=Guid.NewGuid(); //計(jì)算32位,字母加數(shù)字,特別長(zhǎng)的,不重復(fù)的,自增數(shù) public DateTime
          DateTime {get; set; }=DateTime.Now; //每條數(shù)據(jù)的創(chuàng)建時(shí)間 public bool IsRemove { get; set
          ; }//偽刪除的標(biāo)識(shí) } }
          創(chuàng)建BookType類
          using System.ComponentModel.DataAnnotations; namespace Book.Models { public
          class BookType:BaseEntity { [StringLength(20)] public string Name { get; set; }
          } }
          創(chuàng)建Book類
          using System.ComponentModel.DataAnnotations; namespace Book.Models { public
          class Book:BaseEntity { [StringLength(50),Required] public string Name { get;
          set; } public decimal Price { get; set; } } }
          這兩個(gè)類都會(huì)繼承BaseEntity

          在App.Config里面寫上你自己的數(shù)據(jù)庫(kù)連接字符串



          這樣的目的就是去生成數(shù)據(jù)庫(kù),只做生成數(shù)據(jù)庫(kù)的操作。這里只是在Models層寫了一次,在后期加上表示層還有在寫一遍!

          接下來(lái)就是去通過(guò)指令遷移到數(shù)據(jù)庫(kù),操作有三步:

          * 啟動(dòng)遷移:enable-migrations
          * 添加遷移:add-migration '參數(shù)'
          * 更新數(shù)據(jù)庫(kù):update-database(如果你需要添加或者修改某個(gè)字段屬性,只需要進(jìn)行第二步和第三步的操作即可?。?
          記住默認(rèn)項(xiàng)目要選擇你的Models,如果是多個(gè)項(xiàng)目(我這里是只有一個(gè))就必須要把Models設(shè)為啟動(dòng)項(xiàng)目,不然遷移指令可能不會(huì)起到作用





          這樣就表示你的數(shù)據(jù)庫(kù)遷移的工作已經(jīng)完成了,你可以在數(shù)據(jù)庫(kù)進(jìn)行查看



          ?接下來(lái)的工作就是準(zhǔn)備分層的工作,什么是分層?怎么分?好處是什么?

          我的理解:聽某一個(gè)大佬說(shuō),代碼是一層一層寫的不是一行一行寫的。個(gè)人覺得拿捏了。原諒我沒(méi)去百度。。。

          一直覺得對(duì)于面向?qū)ο蟮乃枷?,一直覺得自己才疏學(xué)淺,學(xué)的只是皮毛,真是非常的慚愧。

          剛好借這個(gè)機(jī)會(huì)來(lái)通過(guò)分層一起來(lái)學(xué)習(xí)學(xué)習(xí)。三層,在之前的學(xué)習(xí)中對(duì)于三層也只是找到表示層(UI)、業(yè)務(wù)邏輯層(BLL)、數(shù)據(jù)訪問(wèn)層(DAL)。

          個(gè)人覺得,這樣確實(shí)是解耦了,但是,并沒(méi)有將業(yè)務(wù)邏輯層的“業(yè)務(wù)邏輯”
          這一詞的功能發(fā)揮到極致,就只是簡(jiǎn)單的從UI層get一下BLL層,BLL層簡(jiǎn)單的get一下DAL層。。。(個(gè)人覺得并沒(méi)有解什么耦。。。來(lái)自菜鳥的思考)

          那我們可不可以封一個(gè)接口層,通過(guò)面向?qū)ο蟮睦^承來(lái)去調(diào)整一下呢?

          首先得明確接口是可以繼承接口的!

          創(chuàng)建一個(gè)數(shù)據(jù)接口層IDAL,結(jié)構(gòu)如下:引用Models層



          ?為什么寫這個(gè)接口呢?原因很簡(jiǎn)單,就是將增刪改查等操作進(jìn)行一個(gè)封裝,并且這不是普通的增刪改查,看代碼:


          你可以把它看做是增刪改查的基礎(chǔ)接口,這個(gè)接口是一個(gè)泛型(比如你的商品表,用戶表等等...),它必須得基礎(chǔ)BaseEntity,并且這個(gè)T必須繼承與BaseEntity,也就是必須是BaseEntity的派生類。

          關(guān)于IQueryable的好處注釋以寫!

          這四個(gè)方法就是增刪改查,就算你有幾百?gòu)埍?,?yīng)該也只要寫一次增刪改查的操作就ok(也是來(lái)自菜鳥理解)
          using System; using System.Linq; using Book.Models; namespace IDAL { //
          接口封裝增刪改查的方法它,是個(gè)泛型,并且要給一個(gè)約束,這個(gè)T必須是BaseEntity的派生類也就是子類,別的不行 public interface
          IBaseService<T>where T:BaseEntity { void Add(T t); void Edit(T t); void
          Remove(Guid id); T GetOne(Guid id);//查詢某一個(gè)對(duì)象 //
          IQueryable得到的是一個(gè)集合,它不會(huì)立刻給你去生成Sql語(yǔ)句,直到你需要拿到指定的某個(gè)結(jié)果后,再去給你生成Sql語(yǔ)句,比如根據(jù)條件,分頁(yè),排序等操作獲得的集合數(shù)據(jù)
          IQueryable<T> GetAll(); } }
          既然有了接口,那么肯定是要實(shí)現(xiàn)這個(gè)接口才能調(diào)用里面的增刪改查的四個(gè)方法吧!既然如此,那么就再寫一個(gè)DAL類庫(kù),去實(shí)現(xiàn)這個(gè)接口層。

          結(jié)構(gòu)如下:引用EF以及Models和IDAL層,并且寫一個(gè)BaseService類去實(shí)現(xiàn)IBaseService接口里面的方法



          BaseService代碼如下:
          using IDAL; using System; using System.Linq; using Book.Models; namespace DAL {
          public class BaseService<T> : IBaseService<T> where T:BaseEntity //
          指明這個(gè)T是誰(shuí),就是繼承BaseEntity的類 { public void Add(T t) { throw new
          NotImplementedException(); }public void Edit(T t) { throw new
          NotImplementedException(); }public IQueryable<T> GetAll() { throw new
          NotImplementedException(); }public T GetOne(Guid id) { throw new
          NotImplementedException(); }public void Remove(Guid id) { throw new
          NotImplementedException(); } } }

          前面的?IBaseService<T>就是你實(shí)現(xiàn)的是哪個(gè)接口,后面的Where就是告訴這個(gè)接口要實(shí)現(xiàn)的T(泛型已經(jīng)指定了是繼承BaseEntity的派生類)是誰(shuí)。。。

          可能這里的Where作用還需要去理解一下,個(gè)人理解就是約束、條件之類的作用。

          怎么寫方法?代碼如下:
          using IDAL; using System; using System.Data.Entity; using System.Linq; using
          Book.Models;namespace DAL { public class BaseService<T> : IBaseService<T> where
          T:BaseEntity,new() //指明這個(gè)T是誰(shuí),就是繼承BaseEntity的類 { private BookContext _db=new
          BookContext();public void Add(T t) { //db.Books.Add(t); _db.Set<T>().Add(t); //
          Set<>就是返回一個(gè)DbSet實(shí)例,為什么是T ,作用就是動(dòng)態(tài)的訪問(wèn),無(wú)論是Book還是BookTypes,你給我什么我就用T接就好了
          _db.SaveChanges(); }public void Edit(T t) { _db.Entry(t).State =
          EntityState.Modified;//直接通過(guò)主題去作修改 _db.SaveChanges(); } public IQueryable<T>
          GetAll() {return _db.Set<T>().Where(m => !m.IsRemove).AsNoTracking(); //
          脫離持久態(tài),變?yōu)橛坞x態(tài),并且過(guò)濾掉了已被刪除的數(shù)據(jù) } public T GetOne(Guid id) { return GetAll().First(m
          => m.Id == id);//直接通過(guò)GetAll在通過(guò)id查到你想要的數(shù)據(jù) } public void Remove(Guid id) { var t=
          new T() { Id = id }; //這里是偽刪除,T不能直接new,也是給個(gè)約束條件 new()即可,代表它有構(gòu)造函數(shù)
          _db.Entry(t).State = EntityState.Unchanged;//也是根據(jù)狀態(tài)去刪除 t.IsRemove = true;
          _db.SaveChanges(); } } }


          這些增刪改查方法寫完后,就要去繼承了。原理實(shí)際上和BaseEntity差不多

          既然增刪改查的方法都寫好了,那么怎么去才能調(diào)用到它呢?這個(gè)時(shí)候?yàn)槭裁催€需要去寫IBook和IBookType呢?。
          首先我們?cè)谥笆菍懥薎BaseService這個(gè)接口并且寫了對(duì)應(yīng)的增刪改查方法,但是具體的實(shí)現(xiàn)是在DAL層所有,這兩個(gè)接口只需要繼承對(duì)應(yīng)的IBaseService就好了,具體實(shí)現(xiàn)也是在DAL層,至于DAL層怎么去寫,請(qǐng)看下面的內(nèi)容。

          這個(gè)時(shí)候泛型 T就其作用了,我們可以去寫對(duì)應(yīng)的接口繼承IBaseService就好了。。



          ?代碼如下:

          IBookService:
          namespace IDAL { public interface IBook:IBaseService<Book.Models.Book> { } }
          IBookTypeService:
          using Book.Models; namespace IDAL { public interface
          IBookTypeService:IBaseService<BookType> { } }
          DAL層結(jié)構(gòu):




          為什么還要繼承BaseService?首先BaseService具體實(shí)現(xiàn)了繼承IBaseService的方法,所以,我們只需要繼承一下就可以調(diào)用到BaseService的增刪改查的方法了!

          BookService代碼:
          using Book.Models; using IDAL; namespace DAL { public class
          BookService:BaseService<Book.Models.Book>, IBookService { } }
          BookTypeService代碼:
          using Book.Models; using IDAL; namespace DAL { public class
          BookTypeService:BaseService<BookType>,IBookTypeService { } }
          以上操作完成后,我們只需要實(shí)例化DAL層的Service方法就可以調(diào)用在UI層增刪改查了。

          寫到這里只是最最基礎(chǔ)的底層,如果還要完善需要進(jìn)一步的改善改善。。。

          如果有錯(cuò)誤的地方請(qǐng)?zhí)岢鰜?lái),本人也是學(xué)生,大家都是抱著學(xué)習(xí)的心態(tài)去記錄和鞏固自己的知識(shí)點(diǎn)。。。。。

          友情鏈接
          ioDraw流程圖
          API參考文檔
          OK工具箱
          云服務(wù)器優(yōu)惠
          阿里云優(yōu)惠券
          騰訊云優(yōu)惠券
          京東云優(yōu)惠券
          站點(diǎn)信息
          問(wèn)題反饋
          郵箱:[email protected]
          QQ群:637538335
          關(guān)注微信

                日韩AV免费 | 成人毛片免费观看无需播放器 | 青娱乐91在线 | 叶玉卿三级露全乳视频 | 国产91精品久久久久久久 |