還記得大概一年多前,EF 4.1的時候,小弟我有非常簡單的介紹過Code First,然後就沒消沒息了XDD,其實後續還是有一兩個case有稍微用過這個東西,但是當時用,也不算是真正的Code First,而是偽Code First ( 因為還是先建立DB Table,再利用工具去產生Class… ),而中間,也不斷被真正愛用Code First的人,給問倒問題XDD。
當然,無論是官方的推崇,與國外的論壇,小弟也知道Code First的好處,但沒全力投入,還是無法深深的感覺到;其次,通常都是一人專案,要如何帶到整個Team協同,也是一個問題…特別是DBA反彈的聲音最大…( 還好現在Team裡面的dba很好講話XDD 是個好人~~ );而最近,剛好有機會,就強迫教育了Team member,正式把Code First帶到Team裡面,而Team member裡面使用過的人,都說讚!!( 好險- -||| )
經過一年,EF也已經5.0版本,甚至已經在跑6.0的阿發版本了,官方的各大專案,也使用Code First當作基礎,所以,小弟一年過後,又回來重寫一下之前的文章啦XDDD
What’s Code First
不知道大家是怎樣開始專案的呢?我相信,最常聽到的應該是,看使用者的需求,然後來規劃資料庫,畫出ER圖,然後就開始努力地下去Coding了( 這裡就不討論怎樣軟體開發流程是好是壞了。 )。
接下來呢!?早期小弟在寫ASP的時候,會在裡面加上一堆SQL、邏輯、畫面,組合成義大利麵式的程式碼!( 可惜實際上不夠美味 ),後來使用ASP.NET的時候,也差不了多少,一樣在.cs的檔案裏面放上一堆SQL,只是那時候用Dataset,感覺上比較高級了,後來懂得把Table變成一個又一個的物件,至少有拆開了=w=,到現在,會使用Repository Patten來拆開資料存取層,也會利用EntityFramework來進行ORM,至少有進步了XDD。
但是無論怎樣的設計上,還是會先考慮資料庫模型,想好Table的關聯,畫好ER圖,建好DB後,在開始寫程式。
而這樣的作法,也不是說好或不好,畢竟,沒有不好的方法,只有用錯的地方=w=,但今天,EntityFramework帶來另外一種作法,也就是Code First。( 如果先建立DB,就稱為DB First,如果利用EF工具,先建立好模型,就稱為Model First。)
廢話了一堆,Code First,簡單的說,就是不先建立db,也不用EF的工具建立模型,而是直接利用建立好的類別產生DB!
有沒有很酷!,老實說我覺得酷斃了,尤其是像小弟那麼懶的人,每次想到還要建立Table,真的就懶了…還是寫Class比較親切!?…
建立Code First Demo
首先,我們這個case就用MVC來Demo吧 ( 但不會講到MVC喔 ),建立完MVC後,可以去NuGet檢查一下,是否有Entity Framework套件。
然後,假設我們要寫一個客戶的管理系統,那自然,就要先建立一個客戶的Class,我們新增一個Class,取名為ClientBasic。
接下來呢!?當然就是開始打ClientBasic的程式碼啦!,那db呢!?,別忘了我們現在是Code First,顧名思義,就是先打Code!!
我們建立一個ID,代表唯一的編號,和一個Name,就這麼簡單。
using System; using System.Collections.Generic; using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Web; namespace TestMVC.Models { public class Customer { public int ID { get; set; } public string Name { get; set; } } }
然後,我們要建立另外一個程式碼,這個程式碼主要繼承於DbContext,簡單的說,就像是個資料庫一樣的感覺,而另外要注意的是,我們也要有個建構子,並且傳入字串"name=TestContext",這個字串的意思,是代表,我們App.config( 如果是網頁,則是Web.config ),裡面會有TestContext的連線字串;接下來,我們會設定一個屬性為ClientBasics( 這裡通常會用複數 ),而這個屬性是DbSet型別,而這個屬性,感覺就像是Table一樣。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Data.Entity; namespace MigrationsCodeDemo { public class IMSContext : DbContext { public TestContext() : base("name=TestContext") { } public DbSet<clientbasic> ClientBasics { get; set; } } }
接下來,我們看一下App.config( 或是Web.config ),我們需要一個名稱為TestContext的連線字串,這邊我們使用LocalDB,如果想要連線到SQL Server 2012,就直接給SQL Server 2012的連線字串。
<connectionStrings> <add name="TestContext" providerName="System.Data.SqlClient" connectionString="Data Source=(LocalDb)\v11.0;Initial Catalog=TestContext; Integrated Security=SSPI; AttachDBFilename=|DataDirectory|\TestContext.mdf" /> </connectionStrings>
接下來,我們去修改一下HomeController,在Index的這個Action下,把剛剛打好的TestContext物件給new起來( 變數稱為db ),而這裡面會有許多方法,用來處理所有和資料庫有關的行為,這邊我們new了一個新的Customer物件,並且加入到TestContext裡面( 可以想像成,加上一筆資料),而裡面有屬性Name( 可以想像成欄位Name ),值為Sky,最後利用SaveChanges方法,就會將資料寫回到資料庫。
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using TestMVC.Models; namespace TestMVC.Controllers { public class HomeController : Controller { // GET: /Home/ public ActionResult Index() { var db = new TestContext(); //新增一筆資料 var cust = new Customer(); cust.Name = "Sky"; db.Customers.Add(cust); db.SaveChanges(); return View(); } } }
然後,我們把執行看看。( 當然,View要自己建立阿~@@~ )
當我們去看資料庫,就會發現,他自動地幫我們建立了資料庫和Table!!,神奇吧!!就如前面所說的,我們可以完全不用考慮db該如何建,而會專心思考物件要怎麼寫!!
另外,這邊要特別補充,並不是把TestContext給new出來,db就會自動建立,而是會在真正新增刪除修改查詢db的時候,才會觸發建立db的動作…此外,也別忘記,Linq有延遲載入的功能,所以上面範例,才會使用add當作範例。
如果去查資料,可以查到一筆
後記
小弟這個範例,就是很簡單的先去建立類別,然後資料庫就自動幫忙建立起來了,但是聰明的你應該已經注意到了,那如果Class的屬性增加後,資料庫會不會自動變更!?答案已經很清楚了,在EF他會丟出例外給你看XDD,早期遇到問題,必須先刪除掉資料庫,才能重新Run一次,但現在,EF已經提出新的機制了( 其實一年前就提出了 ) 有興趣的可以參考這篇來解決此問題。