【AaronYang风格】第一篇 CodeFirst 初恋
???????? 原著:Prorgamming Entity Framework Entitywork Code First
???????? 大家好!
???????? 我是AaronYang,這本書我也挺喜歡的,看了一半了,今晚也沒事情,就分享一下一點東西吧
???????? 這本書總共8章,192頁,整體內容看起來也不算吃力的。但是自己認真學的,感覺內容也不多。初學者完全不用害怕自己會不會學會,放心吧,會學會的。
???????? 雖然本書還是基于vs2010 開發的,但是我相信學會這個vs2012那個也會很簡單,再說2010現在也還是主流(但也會對比vs2012的)。當然EF會采用版本EF5的
??????? 內容:Code First介紹,幾種EF編程方式的對比,基本DEMO,Code First生成的數據庫在哪,NuGet在EF中的使用,Migration的問題,其他錯誤處理,Code First 的簡單Convention,配置示例等等,包學會的,親!!!
???????? 讀者約定:
????????? Code First單詞太長了,我簡稱 CF ,以后 我一直都會這樣說哈,不是 騰訊的那個哈。
?
微軟的ADO.NET EntityFramework,簡稱就是大家所說的EF,一個ORM框架。我對ORM的理解就是,按它的語法簡化數據庫的操作,平時都是寫SQL什么的,ORM還有很多,例如NHibernate,Subsonic其他的等等,這里我不想討論這個
?
在Code First出現之前的Model
EF第一次是在VS2008? .NET3.5中 被引進來的。當時工程師們可以用它反向地將數據庫變成一個EDMX后綴名的一個實際上是一個XML的文件。它是可視化的,你可以再次調整你的model去作為你的Domain(三層的朋友的大多都是DAL,其實有的架構模式,其中的Domain類似于三層中的DAL層)。Visual Studio 2010 和 .NET4 又引進來了 EF的第二個版本,你們說的EF4(跟.NET版本一樣,都是4,同樣地,
.NET5,現在已經有EF5了,那么是不是應該學新的呢,我不清楚,如果有技術潔癖的朋友,自己調整一下),在動態創建模型(modeling)的 那一邊,一個新的叫Model First的編程方式被添加進來了。從那以后,你就可以通過可視化界面(edmx文件雙擊后在vs2010里面會有界面,就是那個),你可以在那里面設計(字段,關系等等),然后可以基于你設計的model重新生成數據庫(database)
Model First讓開發者,首先設計模型,在進程中創建數據庫,也就是動態創建數據庫啦。這樣子,你項目運行的時候,使用者,沒有數據庫也能動態創建。
不管你是否通過database-first還是model-first的方式設計了EDMX,這接下來的一步就是讓你的domain層 里面,通過這些model中的實體和關系自動地創建類,生成代碼,到這里開始,開發者就有強類型的類去表現他們的domain中的對象了。有了他們,你就可以很輕松的去操作數據庫了。
還好在.NET4 中,EF有了另一個轉變。以前在NET 3.5中,EF管理內存中的對象,它必須要讓類繼承Entity Framework的EntityObject對象。EntityObject把對象(誰繼承EntityObject的類)的變化傳遞給Entity Framework,從而也就是變成了 跟蹤這些 對象的變化,最后將這些變化持久化到數據庫中去。在.NET4中,除了這個以外,還有個POCO(Plain Old CLR Object)支持,它可以讓EntityFramework跟蹤些簡單的類,而不需要使用EntityObject。這樣可以讓開發者們使用他們自己的類,而不依賴于EntityFramework的了。因為EF 運行時候在內存中會用另一個自己的方式去跟蹤和維護 對象的狀態。
?
?
Code First 到來
在EF4的基礎上,微軟再一次地提供了一種方式去建模(modeling),而且現在已經有很多開發者在使用了----Code First.
Code First允許你 不再使用基于XML的EDMX文件去定義你的domain model
即使Model First和Database First可以讓一些開發者使用他們(技術工具)生成的代碼去解決處理問題,但是許多開發者既不想簡單地使用設計器去處理問題,也不想使用它們生成的類去處理問題,那些人就是想去寫代碼去解決問題。哎~~
所以Code First可以滿足那些人
在Code First中,你可以通過使用POCO類開始定義你的domain model,這些類都不依賴于Entity Framework的。Code First可以完全根據你定義的類的結構去推算出一些信息。你也可以進一步地提供一些額外的配置去描述你的model或者重寫CF推斷的依據的東西。這些配置也是通過code(寫代碼)配置的,不是XML文件或者設計器。
???????? AaronYang 提醒
???????? 當你在使用designer(以前的EF有EDMX文件,雙擊是一個設計器,designer)的時候,EF4已經支持POCO類了。EF團隊提供了 可以幫你生成POCO風格類代碼的 POCO模版。這些類在你在設計器里面操作,做改變的時候,這些生成的類也會自動更新。你可能使用自己POCO類而不是使用工具幫你生成的類。但是如果你這樣做的話,你必須保持類與EDMX同步。這就意味著,設計器改了,你的類你就要手動去改。Code First有個好處,你的類就是Model了,不需要設計器了,這就意味著,你要做改變什么的,你只要改一處,就是改你的 POCO類。
Code First,Database First和Model First都只是生成一些 符合Entity Framework去操作數據 特定規范的類的技術實現方式。一旦有了符合EF的
Model,EF不管你采用什么方式,哪一種技術,運行的時候表現的都是一樣的。所以不管選擇哪一種都是取決于你自己。下面一張圖1-1,簡單地說明了一些EntityFramework的細節
Code First在.NET4的時候,沒有立刻發布,但是也沒有在.NET5的時候帶給開發者,在2011年4月,微軟在發行EntityFramework4.1的時候,順帶把Code First一部分帶給開發者了,當時還沒有把Code First的核心部分發布。接下來,2011年10月 EntityFramework4.2發布了,替代了EF4.1,才真正包含了Code First。這時候,Entity Framework API的核心,System.Data.Entity.dll,已經作為.NET Framework中的一部分。這個dll在EF4.1和4.2是一樣,沒有變化。
Entity Framework4.1也包括了另一個很重要的特征(feature),叫做 DbContext API?????
DbContext是這個API的核心,當然核心還包括了其他的類。DbContext是Entity Framework中ObjectContext的輕量級版本。換句話說,ObjectContext是DbContext的超集,它包括了微軟覺得開發者在使用EF時候經常使用的一些特征
DbContext可以讓你用更簡潔的方式,而不需要使用復雜的ObjectContext的編碼語法,寫更少的代碼去實現很多通用的相同的功能。當使用Code First的時候,這一切更容易發現,通過這個系列的博客,你會慢慢體會到的。
還有本書叫??? Programming Entity Framework: DbContext?? 在講解DbContext,DbSet,驗證API,還有一些其他的DbContext特點的內容的時候,會講的更深點。
通過這幅圖,發現Code First,DbContext是建立在EF4前提上的
?
開始寫 Code First
Code First名字取的很巧妙哈,先寫代碼,再寫其他的。我們先不考慮一些你可能需要用到的場景,我們先大致看下基本功能。這本書剩下的內容都會一直講這個。
???????? AaronYang 說明
???????? 在第一章里面,我們不需要示例代碼。接下來寫的一些代碼只是簡單的例子,不是貫穿全文的示例。從第二章開始,你將會實戰練習。你可以用visual Studio 跟著寫練習,你也可以嘗試不看代碼,自己寫一下。
當然了,第一件事情,我們需要寫一些類去描述我們的 商業領域(domain)。這個例子比較小,就是個 Patient 和 看獸醫的Visit 訪問記錄
我們新建一個控制臺程序吧
添加一個類Patient.cs,代碼如下
using System; using System.Collections.Generic; ? namespace ChapterOneProject { public class Patient { public Patient() { Visits = new List<Visit>(); } public int Id { get; set; } public string Name { get; set; } public DateTime BirthDate { get; set; } public AnimalType AnimalType { get; set; } public DateTime FirstVisit { get; set; } public List<Visit> Visits { get; set; } } ? public class Visit { public int Id { get; set; } public DateTime Date { get; set; } public String ReasonForVisit { get; set; } public String Outcome { get; set; } public Decimal Weight { get; set; } public int PatientId { get; set; } } ? public class AnimalType { public int Id { get; set; } public string TypeName { get; set; } } }?
Code First核心原則----定義一個 讓Code First基于你的類去生成模型的規則。比如說,EF要求一個類要有一個key屬性(主鍵)。CF就會用一個規則,比如說屬性名是否叫 Id,或者組合起來的Id(比如說 PatientId),像這類屬性的名字都會自動地被CF理解為Key。如果按照規則找不到這樣的屬性,它會在運行的時候拋出一個異常,說沒有key。其他一些的轉換規則(convention),決定了string類型的默認長度,或者當你的類繼承了其他的類,也就是子類沒有東西,CF會按照約定給予默認的表結構,CF根據EF可以預測出來的。
如果CF僅僅依賴這點規則去處理你的類,肯定是有限制的。但是CF沒有強加要求去怎么設計去滿足它的處理規則。反過來想想,這些規則已經可以處理一批常見的場合問題了。如果你的類整合遵循這些規則,CF就不需要你再提供其他的配置了。EF將會直接處理你的類。如果你的類沒有遵循約定,你就需要提供其他的配置來保證CF可以正確的理解你的設計。
在這3個類中,Id根據約定,都會是主鍵(key).我們先不添加其他配置,讓CF處理這些類。
?
?
用DbContext管理Object
?
上面的這3個類對Entity Framework來說沒有用,它不認識他們.
但是使用CF就可以了.你就可以使用你自己的類了.如果你使用其他項目的domain層的類,也就是自己的類了,CF將會非常有用了.
為了使用CF,你必須先定義一個類,它是要繼承DbContext的.這個是這些類的角色之一,它會作為一個context(上下文),有了它,CF就知道怎樣去構造你的model了。同樣地,EF也是會理解的,從而跟蹤它們的狀態。這些完成都是靠一個新的類 DbSet。DbSet跟DbContext出生意義差不多。DbContext被包括在ObjectContext中,輕量級的。同樣的,DbSet被包括在EF4的ObjectSet中,輕量級的,使用DbSet可以寫更少的代碼完成一樣的任務。
下面的代碼展示了context的大致樣子。里面有DbSet泛型的Patients和Visits,但是沒有AnimalTypes。CF足夠的智能,它知道Patient會使用到AnimalType類,因此,它也是被包括在這個model中的。通過定義了DbSet,就可以很方便的查詢數據了。
使用NuGet添加對 EntityFramework.dll的引用
或者通過這種方式添加對EntityFramework.dll的引用
輸入 Install-Package EntityFramework??? 然后 回車(下面一節續篇? 我們稍微講下這個控制臺的使用)
?
?
代碼如下
using System.Data.Entity; ? namespace ChapterOneProject { public class VetContext : DbContext { public DbSet<Patient> Patients { get; set; } public DbSet<Visit> Visits { get; set; } } }接下來,我們完全可以利用CF代碼去操作了,它現在已經可以作為我們的數據訪問層了,是不是有點吃驚。這里沒有數據庫連接字符串,甚至不存在數據庫。但是數據訪問層已經準備好了,你已經可以使用了。
打開Program.cs我們添加如下代碼:
using System; using System.Collections.Generic; using System.Linq; using System.Text; ? namespace ChapterOneProject { class Program { static void Main(string[] args) { var dog = new AnimalType { TypeName = "Dog" }; var patient = new Patient { Name = "Sampson", BirthDate = new DateTime(2008, 1, 28), AnimalType = dog, FirstVisit = new DateTime(2008, 1, 28), Visits = new List<Visit> { new Visit { Date = new DateTime(2011, 9, 1) } } }; ? using (var context = new VetContext()) { context.Patients.Add(patient); context.SaveChanges(); } Console.WriteLine("錄入成功!"); Console.ReadKey(); } } }創建一個動物類型,狗
然后創建一個病的狗,來看獸醫是在2011年9月1日,就一次記錄,還有其他關于狗的信息
接下來我們是CF語法把這條狗的病情和記錄存到數據庫中去
運行項目!!
?
?
?
?
數據庫生成的位置
?
?
只要你的電腦裝了 VS2012(不在乎你的電腦是否裝了vs2010),默認CodeFirst配置生成數據庫位置都會在localdb
VS2012還有種方式查看數據庫SQL Server對象資源管理器
如果你的電腦只裝了VS2010,如果你裝了SQLExpress默認在 SQLExpress上
EF CodeFirst會根據你使用VS2010開發還是VS2012開發
會生成稍微不同的配置文件
我現在的電腦上裝的是VS2010和2012都有,生成的App.config如下
上面基本一樣的
注意下面的entityFramework那個節點
這里默認的是LocalDbConnectionFactory.EntityFramework,所以這個項目默認生成的數據庫在LocalDb上
?
?
如果想生成在最常見的那種SQLServer上,你可以entityFramework節點下的內容改下
?
方式一:
親,你現在還陌生嗎?同樣的不想使用sqlexpress,你自己換成其他的數據庫連接字符串方式就行了
?
方式二:
加一個ConnectionStrings的節點
關于packages.config配置文件,我畫紅圈的地方不一樣,看你使用的.netframework,vs2012應該是net45
?
如果需要SQLExpress 2008 R2的伙伴,可以到這里官網 下載
???????? AaronYang 提醒
???????? Code First中 Convention這個單詞
Convention 這個單詞我個人理解是 規定,約定。 寫CodeFirst的人,如果你的類符合Convention,CodeFirst就能認識,然后它就能夠按照已經定義好的Convention去處理你的類,生成你想要的數據庫結構,然后你就可以利用EntityFramework操作數據庫了。比如說Visit類中的PatientId符合Convention,這里自動處理成外鍵了。int類型,是其他類的名字+Id
?????????? 再比如說,VetContext中沒有聲明DbSet<AnimalType>但是CodeFirst也會幫我們生成,它好像什么都知道的樣子原因是你寫的Code符合它的Convention了。還有很多其他的Convention,我們后面幾章講解到的。
????????? 后面的內容,我會經常說到Convention,到時候,我可不解釋咯。如果想要具體添加或者修改Convention,我們可以通過配置完成,當然這里肯定不是DatabaseFirst或者ModelFirst中的 designer可視化操實際上XML文件的EDMX文件。具體的后面說吧
?
?
各種方式是如何把Class們變成數據庫的,如圖
?
這個就好比?? 用VC++,VB,C#等.net語言,不管前面怎么弄,最終會變成中間代碼(IL)才能被機器識別
也就是說DataBase First,? Model Fitst,Code First 最終都是變成內存中的對象,EntityFramework能夠識別的(例如EntityType,AssociatonType),然后就可以跟蹤,持久化數據操作等等。
?
?
?
簡單的配置了解
Code First主要有兩種,第一種是Data Annotations,? 第二種是Fluent API
第二種的方式的配置更強大點,也就是說,DataAnnotations的功能是Fluent API功能的子集,但是DataAnnotations使用起來更簡潔
?
======Data Annotations小例子====
我們應該發現AnimalTypes那張表中,可以為空,我們不希望為空,怎么做?
我們只要在TypeName屬性上加一個Required
此時再次 運行項目,
會發生這個錯誤。因為模型改變了,建議我使用Code First Migrations去更新數據庫。這里講到了Migrations(遷移)
我們先解決這個問題
我們打開? 包資源管理器控制臺,輸入enable-Migrations?? 大小寫無所謂
運行后會生成一個文件夾,后面的20130829020525什么的是時間戳,讓每次的Migration都不會出現重復的文件名
如果 你還遇到一個這樣的問題(我是遇到了):
比如我嘗試重新安裝EntityFramework,因為我一開項目在家里的電腦的vs,然后用的公司電腦的vs,兩個vs的NuGet版本
不一樣,所以會報如下的錯誤,你只要重新安裝最新版本的NuGet,就是保證兩個前一次使用的NuGet版本和現在的要一樣就行了
接下來,我們執行? add-migration AddRequiredOnAnimalType_TypeName(包管理控制臺中執行)
添加一次遷移
然后我們執行update-database
刷新數據庫,TypeName變成not null了,說白了每次的update-database命令都是轉換成sql去執行、在后面 update-database –verbose? 就可以查看這次遷移的sql語句了。
加了Required后就像ASP.NET MVC3中那樣,Model中的屬性就具有驗證的功能了,如果為空,EF就會拋出異常的
?
由于客戶機器上沒有vs,所以你可以把這段sql拷過去,作為本次版本數據庫的改變了
?
我們再在 AnimalType上加上Table注解,里面就是最新的表名稱
我再做一次遷移? 復習一下過程
1.??? add-migration UpdateAnimalTypeTableNameToSpecies
2.??? update-database –verbose
?
?
?
======Fluent API小例子====
同樣的過程,我們使用Fluent API操作下
打開VetContext類,重寫OnModelCreating方法,添加一些代碼,估計一看就能看懂了,這里不細說了
using System.Data.Entity; ? namespace ChapterOneProject { public class VetContext : DbContext { public DbSet<Patient> Patients { get; set; } public DbSet<Visit> Visits { get; set; } ? protected override void OnModelCreating (DbModelBuilder modelBuilder) { modelBuilder.Entity<AnimalType>() .ToTable("Species"); modelBuilder.Entity<AnimalType>() .Property(p => p.TypeName).IsRequired(); } } }判斷開發者使用了那種EF模式,下面有張圖判斷
這里不做具體討論了
最后留言
?
關于這本書,重點是在講使用Code First構建和配置模型(Model).是 Programming Entity Framework (second edition)這本書的拓展。還有一本書叫Programming Entity Framework: DbContext,主要重點在DbContext, DbSet, Validation API,還有些EntityFramework NuGet? 包的一些功能的使用講解
?
?
?
?
代碼下載: 下載
注意,可能我們的NuGet的包不太一樣,所以運行時候可能有錯誤,所以代碼僅供參考.如果有疑問,親留言….
?
本文章是 Http://AaronYang.cnblogs.com? AaronYang(楊洋)辛苦寫的,轉載時候,請標明出處
總結
以上是生活随笔為你收集整理的【AaronYang风格】第一篇 CodeFirst 初恋的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 检测某个IP是否属于某个网段范围
- 下一篇: Android adt 初步理解和分析(