在開發專案時很多時候若有連接到資料庫,通常會把 Model 這個部分先切割出來開發,這樣可以讓 Model 獨立在主 project 之外讓其他 projects 可以一起使用,在維護的時候其實也會比較方便只需要抽換DLL就好(這也算關注點分離嗎),另外就是 Model 天生就比較能夠獨立出來開發。不過在獨立開發 Model 的時候也要注意一些小東西。今天使用 Entity Framework (version 5) 的 Code First with existing database 的方式來做個示範。
實作部分#
我們選用的 Database 是赫赫有名的 Northwind 資料庫,我想這個資料庫大家應該都比我還熟了。這次我們選出 Products 和 Categories 這兩個資料表來做示範的 Table 吧~!順便提醒一下用 Code First with existing database 時會有些小地方需要注意!
首先~我們就來把 Northwind database bring online 吧~
把資料庫 online 後,接下來就切到 Visual Studio 中創一個新的 Class Library 專案吧~
專案名稱就隨便給個 Project.Model 來代表這個 DLL 是我們的 Model。而因為要用 Entity Framework 的 Code First 功能,我們要引用一個 EF 的 DLL:EntityFramework,若是用 Nuget 來安裝的話會連同 System.Data.Entity 這個 DLL 一起裝,不過若是沒有要用視覺設計工具來輔助的話其實是可以不用這個 DLL 的。
使用 Code First 的方式來與資料庫做互動的話需要撰寫一個繼承 DbContext 的類別。這裡我們就把這個類別名稱取為 Northwind。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| using System.Data.Entity;
///這邊我們只用到Products與Categories這兩個資料表做示範。
///DbSet這個類別代表一組在Context中的實體資料集合,但要注意這個集合內的型別(class)都是相同的,
///不能接受複合型別,像是DbSet<Product,Category>(這邊型別相當於資料庫中的資料表的概念)。
public class Northwind : DbContext
{
// 這裡的屬性名稱要注意,需要與資料表的名稱相同!
// 2012-11-16更正!
// 這邊要注意的應該是DbSet裡的名稱,(也就是Product與Catagory)
// Case 1:沒有貼Table標籤
// Code-First預設會依據DbContext中DbSet的泛型名稱(這裡就是Products, Catagories)作為
// 資料庫中對應的表格名稱。若資料庫中沒有這個表格Code First會幫你產生(很貼心吧,千萬小心)。
// Case 2:Product有貼Table標籤
// Code-First會依據標籤所給予的名稱來做為對應到資料庫中的表格名稱。
public DbSet<Product> Products { get; set; }
public DbSet<Category> Categories { get; set; }
}
|
而另外兩個資料表則如下撰寫:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| using System.ComponentModel.DataAnnotations.Schema;
public class Product
{
// Code-First 的預設欄位對應會自動把ID結尾的屬性辨識為PrimaryKey,但可以用[Key]標籤來輔助。
public int ProductID { get; set; }
public string ProductName { get; set; }
public Decimal? UnitPrice { get; set; }
public bool Discontinued { get; set; }
/// 注意!使用 Code First 連接既有資料庫沒有加上這個 Schema 標籤會出錯誤!
/// 因為使用Category與Product資料表,因此需要將這兩張表格的關係寫明。
/// 若是只引用Product資料表則不用寫也沒關係。
/// 當然若兩張表格彼此沒有直接關係的話也不用寫這個。
[ForeignKey("Category")]
public int CategoryID { get; set; }
public virtual Category Category { get; set; }
}
|
另外一張資料表(Category)如下:
1
2
3
4
5
6
7
8
9
10
| using System.Collections.Generic;
public class Category
{
public int CategoryID { get; set; }
public string CategoryName { get; set; }
public string Description { get; set; }
public byte[] Picture { get; set; }
public virtual ICollection<product> Products { get; set; }
}
|
另外我們撰寫另外一個類別來使用Northwind至這個類別(或是說資料庫)~
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
| public class NorthwindRepository : IDisposable
{
private Northwind _db;
//這裡的資料存取為求簡單沒有做依賴注入的動作。
public NorthwindRepository()
{
_db = new Northwind();
}
public ICollection<string> ListAllProductName()
{
return _db.Products.Select(a => a.ProductName).ToList();
}
public ICollection<string> ListAllCategoryName()
{
return _db.Categories.Select(a => a.CategoryName).ToList();
}
public void Dispose()
{
if (_db != null)
_db.Dispose();
}
}
|
接下來就是要注意的就是使用 Code First with existing database 時並不會自動幫我們把連線字串準備好,這必須得自行撰寫。因此我們在 App.config (這個檔案會在安裝 Entity Framework 的時候幫我們把基本的東西宣告好)中,需要加入一段 connectionStrings 標籤~
1
2
3
| <add name="Northwind"
connectionString="Data Source=your source;Initial Catalog=Northwind;User Id=uid;Password=pwd"
providerName="System.Data.SqlClient"/>
|
若不確定連線字串如何撰寫可以參考這個網頁,裡面有很多資料庫的連線字串撰寫方法。
以上都寫好了之後其實就可以來使用我們的 Northwind 資料庫了~這邊我們新創一個空的 web form 專案,首先我們要先把我們的連線字串放置 web.config 中,然後就是引用 Project.Model.dll 了~!不過這邊要注意,引用的 dll 不能把 copy local 設為 false,否則在 create 物件時會出現錯誤!
另外使用於 console 專案時,也可以直接把 App.config 複製過去,一樣參考 DLL 時 copy local 設為 true 就可以直接拿來用了!像是這樣~
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| using Project.Model;
static void Main(string[] args)
{
// 能用using時儘量用,至少沒有害處。
using (NorthwindRepository db = new NorthwindRepository())
{
foreach (var item in db.ListAllProductName())
{
Console.WriteLine("item name: {0}", item);
}
}
Console.WriteLine("\nFinish!");
Console.Read();
}
|