2013年5月30日

Entity Framework - 使用Code First模式 Ver 5.0

還記得大概一年多前,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套件。

image

然後,假設我們要寫一個客戶的管理系統,那自然,就要先建立一個客戶的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當作範例。

image

如果去查資料,可以查到一筆

image

後記

小弟這個範例,就是很簡單的先去建立類別,然後資料庫就自動幫忙建立起來了,但是聰明的你應該已經注意到了,那如果Class的屬性增加後,資料庫會不會自動變更!?答案已經很清楚了,在EF他會丟出例外給你看XDD,早期遇到問題,必須先刪除掉資料庫,才能重新Run一次,但現在,EF已經提出新的機制了( 其實一年前就提出了 ) 有興趣的可以參考這篇來解決此問題。

參考資料

  • http://msdn.microsoft.com/zh-tw/data/ee712907
  • 2013年5月29日

    Visual Studio - 使用不同身分開啟VS2012

    這篇大概是有史以來最簡短的一篇…但這個功能,有的時候做Demo又會用到,不記錄一下,我又常常會忘記…所以這邊稍微紀錄一下 ( 其實這招是偷學百敬老師的XDD )。

    這個功能很簡單,就是使用不同的身分開啟VS2012(其實2010應該也可以),我們只要在VS2012的圖示上,按下shift加上滑鼠右鍵,就可以在跳出的選單中,看到"以不同的使用者身分執行"。

    image

    按下後,就需要輸入另外一位使用者的帳號密碼,完成後,就可以以不同的身分進入VS2012了。

    image

    就這麼簡單…純粹記錄文XDDD

    參考資料

    • 百敬老師XDD

    Entity Framework - 出現Cannot attach the file錯誤

    這篇也是小小的紀錄文,稍微紀錄一下。

    最近玩Entity Framework Code First玩得很大,而前一陣子,使用Code First的時候,要更新資料庫,卻出現Cannot attach the file的錯誤。如下圖。

    image

    Cannot attach the file 'C:\xxx專案\bin\Debug\xxx.mdf' as database 'xxxdb'.

    其實Cannot attach the file的錯誤,有滿多種可能的,但這邊的情況主要是因為如下;這是這次發生問題的專案結構,小弟有分為主要的MVC專案和專門管Model的Model專案,而問題,主要是Web.config和App.config這邊。

    image

    好的,那為什麼會發生這個問題呢!!?其實很簡單,那是因為路徑上的問題與錯誤。

    我們先用SSMS來看一下真正的mdf檔案在哪邊;當然,很對不起,很多東西都被反白掉了,但如果仔細看,我們可以發現mdf檔案和ldf檔案都在App_Data底下。

    image

    接下來,我們回頭看看MVC專案底下的Web.Config;是的,connectionString裡面的AttachDbFilename參數,指向的檔案位置是DataDirectory,其實這就是代表著指著專案底下的App_Data目錄;以上面的例子來說,就是MVC專案底下的App_Data目錄。

    image

    但實際上,當我們下達Updata-database指令的時候,卻是針對Model專案,如下圖。

    image

    那我們看一下Model底下的App.config,可以發現,也有AttachDbFilename的參數,而且也是指向著App_Data目錄,但其實我們真正的資料庫卻是在MVC專案的App_Data目錄阿!!

    是的,所以當Updata-Database的時候,就會發生這種錯誤,因為資料庫的檔案,實際上根本就不存在Model專案的App_Data目錄下~~

    所以解決的方式很簡單,我們只要把Model專案的App.config的ConnectionString的AttachDbFilename拿掉,就可以了,如下圖。

    image

    這樣在一次的updata-database就不會有問題了。