【AaronYang風格】第一篇 CodeFirst 初戀


image         原著: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 ,以后 我一直都會這樣說哈,不是 騰訊的那個哈。



第一章 歡迎 Code First
 

 

微軟的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的細節

image

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特點的內容的時候,會講的更深點。

image通過這幅圖,發現Code First,DbContext是建立在EF4前提上的

 

開始寫 Code First

Code First名字取的很巧妙哈,先寫代碼,再寫其他的。我們先不考慮一些你可能需要用到的場景,我們先大致看下基本功能。這本書剩下的內容都會一直講這個。

         AaronYang 說明

         在第一章里面,我們不需要示例代碼。接下來寫的一些代碼只是簡單的例子,不是貫穿全文的示例。從第二章開始,你將會實戰練習。你可以用visual Studio 跟着寫練習,你也可以嘗試不看代碼,自己寫一下。

當然了,第一件事情,我們需要寫一些類去描述我們的 商業領域(domain)。這個例子比較小,就是個 Patient 和 看獸醫的Visit 訪問記錄

我們新建一個控制台程序吧

imageimage

添加一個類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,就可以很方便的查詢數據了。image

使用NuGet添加對 EntityFramework.dll的引用

imageimage

或者通過這種方式添加對EntityFramework.dll的引用

image

輸入 Install-Package EntityFramework    然后 回車(下面一節續篇  我們稍微講下這個控制台的使用)

image

 

 

代碼如下

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語法把這條狗的病情和記錄存到數據庫中去

運行項目!!

image

 

 


 

 

 

數據庫生成的位置

 

imageimage

 

只要你的電腦裝了 VS2012(不在乎你的電腦是否裝了vs2010),默認CodeFirst配置生成數據庫位置都會在localdb

imageimage

VS2012還有種方式查看數據庫SQL Server對象資源管理器

imageimage

如果你的電腦只裝了VS2010,如果你裝了SQLExpress默認在 SQLExpress上

image

EF CodeFirst會根據你使用VS2010開發還是VS2012開發

會生成稍微不同的配置文件

我現在的電腦上裝的是VS2010和2012都有,生成的App.config如下

image

上面基本一樣的

注意下面的entityFramework那個節點

這里默認的是LocalDbConnectionFactory.EntityFramework,所以這個項目默認生成的數據庫在LocalDb上

 

 

如果想生成在最常見的那種SQLServer上,你可以entityFramework節點下的內容改下

 

方式一:

imageimage

親,你現在還陌生嗎?同樣的不想使用sqlexpress,你自己換成其他的數據庫連接字符串方式就行了

 

方式二:

加一個ConnectionStrings的節點

image

關於packages.config配置文件,我畫紅圈的地方不一樣,看你使用的.netframework,vs2012應該是net45

image

 

如果需要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們變成數據庫的,如圖

 

image

這個就好比   用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那張表中,可以為空,我們不希望為空,怎么做?

image

我們只要在TypeName屬性上加一個Required

imageimage

此時再次 運行項目,

會發生這個錯誤。因為模型改變了,建議我使用Code First Migrations去更新數據庫。這里講到了Migrations(遷移)

image

我們先解決這個問題

我們打開  包資源管理器控制台,輸入enable-Migrations   大小寫無所謂

image

運行后會生成一個文件夾,后面的20130829020525什么的是時間戳,讓每次的Migration都不會出現重復的文件名

image

如果 你還遇到一個這樣的問題(我是遇到了):

比如我嘗試重新安裝EntityFramework,因為我一開項目在家里的電腦的vs,然后用的公司電腦的vs,兩個vs的NuGet版本

不一樣,所以會報如下的錯誤,你只要重新安裝最新版本的NuGet,就是保證兩個前一次使用的NuGet版本和現在的要一樣就行了

image

接下來,我們執行  add-migration AddRequiredOnAnimalType_TypeName(包管理控制台中執行)

添加一次遷移

image

然后我們執行update-database

image

刷新數據庫,TypeName變成not null了,說白了每次的update-database命令都是轉換成sql去執行、在后面 update-database –verbose  就可以查看這次遷移的sql語句了。

加了Required后就像ASP.NET MVC3中那樣,Model中的屬性就具有驗證的功能了,如果為空,EF就會拋出異常的

 

由於客戶機器上沒有vs,所以你可以把這段sql拷過去,作為本次版本數據庫的改變了

image

 

我們再在 AnimalType上加上Table注解,里面就是最新的表名稱

image

我再做一次遷移  復習一下過程

1.    add-migration UpdateAnimalTypeTableNameToSpecies

2.    update-database –verbose

image

image

 

 

 

======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模式,下面有張圖判斷

image

這里不做具體討論了





 

最后留言

 

關於這本書,重點是在講使用Code First構建和配置模型(Model).是 Programming Entity Framework (second edition)這本書的拓展。還有一本書叫Programming Entity Framework: DbContext,主要重點在DbContext, DbSet, Validation API,還有些EntityFramework NuGet  包的一些功能的使用講解

 

 

 

 

代碼下載: 下載

注意,可能我們的NuGet的包不太一樣,所以運行時候可能有錯誤,所以代碼僅供參考.如果有疑問,親留言….

 

 

本文章是 Http://AaronYang.cnblogs.com  AaronYang(楊洋)辛苦寫的,轉載時候,請標明出處


免責聲明!

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



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