本文轉載:https://www.cnblogs.com/dotnet261010/p/7119351.html
EF的核心程式集位於System.Data.Entity.dll和System.Data.EntityFramework.dll中。
支援CodeFirst的位於EntityFramework.dll中。
通常使用NuGet Package Manager來新增這些程式集。
如果沒有資料庫:
1、先寫程式碼,自動建立資料庫。
2、如果程式碼有變化,自動刪除資料庫重建,或者是使用遷移功能更改已有資料庫。
如果已有資料庫:
1、使用EF PowerTools反向工程生成模型。
下面的示例程式中將透過一個控制檯程式演示如何透過Code First模式建立一個資料庫,並執行簡單的增刪改查操作。
一、建立一個控制檯應用程式,命名為CodeFirstAppDemo。
二、安裝Entity Framework,新增對Code First的支援
1、透過Nuget包管理器控制檯進行安裝
選擇“工具”->Nuget程式包管理器->程式包管理器控制檯,下面將會開啟程式包管理器控制檯視窗:
輸入命令:Install-Package EntityFramework進行安裝。
2、透過視覺化介面進行安裝
在專案上面右鍵選擇管理Nuget程式包:
選擇EntityFramework,點選“安裝”按鈕進行安裝:
安裝完以後,專案引用裡面將會出現EntityFramework程式集:
如果安裝完以後,專案引用裡面沒有這兩個dll,一定要檢查為什麼沒有安裝成功,因為下面的程式中要用到DbContext類,該類位於EntityFramework程式集中。
三、根據.NET中的類來建立資料庫。
經過上面的步驟之後,我們就可以開始寫程式碼了。在寫程式碼之前,要始終記得:每個實體類就是相應的資料表中的一行資料,該實體類的屬性對應的就是資料表中的列。
1、建立EDM實體資料模型
在專案上右鍵->新增->新建資料夾,命名為Models,存放相應的實體類。在Models資料夾下面新建兩個實體類:Category和Product,Category裡面包含一個型別是Product的集合屬性,兩個實體類的屬性分別如下:
Category類:
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5
6 namespace CodeFirstAppDemo.Models
7 {
8 /// <summary>
9 /// 產品分類表
10 /// </summary>
11 public class Category
12 {
13 /// <summary>
14 /// 分類ID
15 /// </summary>
16 public int CategoryId { get; set; }
17
18 /// <summary>
19 /// 分類名稱
20 /// </summary>
21 public string CategoryName { get; set; }
22
23 /// <summary>
24 /// 產品
25 /// </summary>
26 public List<Product> ProductList { get; set; }
27 }
28 }
Produce類:
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5
6 namespace CodeFirstAppDemo.Models
7 {
8 /// <summary>
9 /// 產品類
10 /// </summary>
11 public class Product
12 {
13 /// <summary>
14 /// 產品Id
15 /// </summary>
16 public int Id { get; set; }
17
18 /// <summary>
19 /// 產品名稱
20 /// </summary>
21 public string ProductName { get; set; }
22
23 /// <summary>
24 /// 產品價格
25 /// </summary>
26 public decimal Price { get; set; }
27
28 /// <summary>
29 /// 出版日期
30 /// </summary>
31 public DateTime PublicDate { get; set; }
32 }
33 }
我們需要定義和期望的資料庫型別相匹配的屬性。上面的例子中,.Net中的int型別會對映到SQL Server中的int型別,string型別會對映到所有可能的字元型別,decimal和Datetime也和SQL Server中的一樣。大多數時候,我們不需要關心這些細節,我們只需要編寫能夠表示資料的模型類就行了,然後使用標準的.Net型別定義屬性,其他的就讓EF自己計算出儲存資料所需要的RDBMS型別。
2、建立資料上下文
接下來我們建立資料庫上下文,它是資料庫的抽象。目前,我們有兩張張表Category和Product,因而要給該資料庫上下文定義兩個屬性來代表這兩張表。再者,一張表中一般肯定不止一條資料行,所以我們必須定義一個集合屬性,EF使用DbSet來實現這個目的。
在專案上右鍵->新增->新建資料夾,命名為EFDbContext,用來存放資料庫上下文類。新增類Context,並使該類繼承自DbContext類。DbContext位於EntityFramework.dll程式集中。
Context類程式碼如下:
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Data.Entity;
6 using CodeFirstAppDemo.Models;
7
8 namespace CodeFirstAppDemo.EFDbContext
9 {
10 public class Context : DbContext
11 {
12 /// <summary>
13 /// 1、建立建構函式,建構函式繼承DbContext類的建構函式,透過DbContext類的建構函式建立資料庫連線
14 /// 2、DbContext類的建構函式里面的引數是資料庫連線字串,透過該連線字串去建立資料庫
15 /// </summary>
16 public Context()
17 : base("name=FirstCodeFirstApp")
18 { }
19
20 //2、定義資料集合:用於建立表
21 public DbSet<Category> Categorys { get; set; }
22
23 public DbSet<Product> Products { get; set; }
24 }
25 }
在這裡,DbContext是所有基於EF的上下文基類,透過它可以訪問到資料庫中的所有表。上面的程式碼中呼叫了父類的建構函式,並且傳入了一個鍵值對,鍵是name,值是CodeFirstApp,這個鍵值對是定義在應用程式的配置檔案中的,取決於你的應用程式型別,可能是app.config或者web.config。在我們的控制檯應用程式中就是app.config。
在app.config檔案的configuration節點下(不要在第一個節點下,否則會報錯)新增:
1 <connectionStrings>
2 <add name="CodeFirstApp" connectionString="Server=.;Database=CodeFirstApp;User Id=sa;Password=test" providerName="System.Data.SqlClient"/>
3 </connectionStrings>
3、使用EF提供的API訪問資料庫來建立資料庫
1 using CodeFirstAppDemo.EFDbContext;
2 using System;
3 using System.Collections.Generic;
4 using System.Linq;
5 using System.Text;
6
7 namespace CodeFirstAppDemo
8 {
9 class Program
10 {
11 static void Main(string[] args)
12 {
13 // 使用資料庫上下文Context
14 using (var context = new Context())
15 {
16 // 如果資料庫不存在,則呼叫EF內建的API建立資料庫
17 if (context.Database.CreateIfNotExists())
18 {
19 Console.WriteLine("資料庫建立成功!");
20 }
21 else
22 {
23 Console.WriteLine("資料庫已存在");
24 }
25 }
26
27 Console.ReadKey();
28 }
29 }
30 }
最後,只需要確保連線字串沒有問題就可以了。執行程式,然後開啟SSMS進行確認資料庫是否建立成功即可。
這時可以清楚地看到,資料庫表名是自定義資料庫上下文中DbSet<T>屬性中T型別的複數形式。例如T型別是Product,那麼生成的表名就是Products,而表中的列是資料模型的屬性。此外,注意以下列的型別。EF預設將id作為了主鍵,string型別的ProductName在資料庫中的型別是nvarchar(max),這些都是在使用EF時必須注意的命名規格。
四、執行簡單的CRUD操作
1、建立記錄-Create
你可以這樣認為,將物件新增到集合中就相當於將資料插入到資料庫相應的表中。我們使用DbSet的Add方法來實現新資料的新增,而DbContext類的SaveChanges方法會將未處理的更改提交到資料庫,這是透過檢測上下文中所有的物件的狀態來完成的。所有的物件都駐留在上下文類的DbSet屬性中。比如,例子中有一個Products屬性,那麼所有的產品資料都會儲存到這個泛型集合屬性中。資料庫上下文會跟蹤DbSet屬性中的所有物件的狀態,這些狀態有這麼幾種:Deleted、Added、Modified和Unchanged。如果你想在一個表中插入多行資料,那麼只需要新增該表對應的類的多個物件的例項即可,然後使用SaveChanges方法將更改提交到資料庫,該方法是以單事務執行的。最終,所有的資料庫更改都會以單個工作單元持久化。既然是事務,那麼就允許將批次相關的更改作為單個操作提交,這樣就保證了事務一致性和資料完整性。
修改Main方法如下:
1 using CodeFirstAppDemo.EFDbContext;
2 using CodeFirstAppDemo.Models;
3 using System;
4 using System.Collections.Generic;
5 using System.Linq;
6 using System.Text;
7
8 namespace CodeFirstAppDemo
9 {
10 class Program
11 {
12 static void Main(string[] args)
13 {
14 // 使用資料庫上下文Context
15 using (var context = new Context())
16 {
17 // 如果資料庫不存在,則呼叫EF內建的API建立資料庫
18 if (context.Database.CreateIfNotExists())
19 {
20 Console.WriteLine("資料庫建立成功!");
21 }
22 else
23 {
24 Console.WriteLine("資料庫已存在");
25 }
26
27 #region EF 新增資料
28 //新增資料
29 var cate = new List<Category> {
30 new Category{
31 CategoryName="文學類",
32 ProductList=new List<Product>{
33 new Product
34 {
35 ProductName="百年孤獨",
36 Price=37.53m,
37 PublicDate=new DateTime(2011,6,1)
38
39 },
40 new Product
41 {
42 ProductName="老人與海",
43 Price=37.53m,
44 PublicDate=new DateTime(2010,6,1)
45
46 }
47 }
48 },
49 new Category{
50 CategoryName="計算機類",
51 ProductList=new List<Product>{
52 new Product
53 {
54 ProductName="C#高階程式設計第九版",
55 Price=48.23m,
56 PublicDate=new DateTime(2016,2,8)
57 },
58 new Product
59 {
60 ProductName="Oracle從入門到精通",
61 Price=27.03m,
62 PublicDate=new DateTime(2014,7,9)
63 }
64 }
65 }
66
67 };
68
69 //將建立的集合新增到上下文中
70 context.Categorys.AddRange(cate);
71 //呼叫SaveChanges()方法,將資料插入到資料庫
72 context.SaveChanges();
73 #endregion
74 }
75
76 Console.ReadKey();
77 }
78 }
79 }
這裡需要注意兩點:
1、不需要給Product.Id屬性賦值,因為它對應到SQL Server表中的主鍵列,它的值是自動生成的,當SaveChanges執行以後,打斷點就能看到返回的Product.Id已經有值了。
2、Context的例項用了using語句包裝起來,這是因為DbContext實現了IDisposable介面。DbContext還包含了DbConnection的例項,該例項指向了具有特定連線字串的資料庫。在EF中合適地釋放資料庫連線和ADO.NET中同等重要。
2、查詢記錄-Retrieve
查詢時也是直接透過DbSet進行查詢的:
1 using CodeFirstAppDemo.EFDbContext;
2 using CodeFirstAppDemo.Models;
3 using System;
4 using System.Collections.Generic;
5 using System.Linq;
6 using System.Text;
7
8 namespace CodeFirstAppDemo
9 {
10 class Program
11 {
12 static void Main(string[] args)
13 {
14 // 使用資料庫上下文Context
15 using (var context = new Context())
16 {
17 // 如果資料庫不存在,則呼叫EF內建的API建立資料庫
18 if (context.Database.CreateIfNotExists())
19 {
20 Console.WriteLine("資料庫建立成功!");
21 }
22 else
23 {
24 Console.WriteLine("資料庫已存在");
25 }
26
27 #region EF 2查詢資料
28
29 //查詢方式1
30 var products = from p in context.Categorys select p;
31 foreach (var item in products)
32 {
33 Console.WriteLine("分類名稱:" + item.CategoryName);
34 }
35
36 //查詢方式2
37 //延遲載入 cates裡面沒有資料
38 var cates = context.Categorys;
39 //執行迭代的時候才有資料
40 foreach (var item in cates)
41 {
42 Console.WriteLine("分類名稱:" + item.CategoryName);
43 }
44 #endregion
45 }
46
47 Console.ReadKey();
48 }
49 }
50 }
如果像下面那樣打一個斷點,你會看到一個結果檢視,點選類似重新整理的圖示會看到查詢的結果,這個東西道出了EF中很重要的一個概念:延遲載入。此時還沒有真正查詢資料庫,只有當LINQ的查詢結果被訪問或者被列舉時才會將查詢命令傳送到資料庫。EF是基於DbSet實現的IQueryable介面來處理延遲查詢的。
3、更新記錄-Update
在SQL中,更新需要執行Update命令。而在EF中,我們要找到DbSet實體集合中要更新的物件,然後修改其屬性,最後呼叫SaveChanges方法即可。
using CodeFirstAppDemo.EFDbContext;
using CodeFirstAppDemo.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace CodeFirstAppDemo
{
class Program
{
static void Main(string[] args)
{
// 使用資料庫上下文Context
using (var context = new Context())
{
// 如果資料庫不存在,則呼叫EF內建的API建立資料庫
if (context.Database.CreateIfNotExists())
{
Console.WriteLine("資料庫建立成功!");
}
else
{
Console.WriteLine("資料庫已存在");
}
#region EF 更新資料
var products = context.Products;
if (products.Any())
{
// 查詢產品名稱是“百年孤獨”的產品
var toUpdateProduct = products.First(p => p.ProductName == "百年孤獨");
// 修改查詢出的產品名稱
toUpdateProduct.ProductName = "唐詩三百首";
// 呼叫SaveChanges()方法儲存資料
context.SaveChanges();
}
#endregion
}
Console.ReadKey();
}
}
}
這裡我們使用了Any()擴充套件方法來判斷序列中是否有元素,然後使用First()擴充套件方法來找到Name=="百年孤獨"的元素,然後給目標物件的Name屬性賦予新值,最後呼叫SaveChanges()方法儲存資料。
4、刪除記錄-Delete
要刪除一條資料,就要先找到這條資料.
1 using CodeFirstAppDemo.EFDbContext;
2 using CodeFirstAppDemo.Models;
3 using System;
4 using System.Collections.Generic;
5 using System.Data.Entity;
6 using System.Linq;
7 using System.Text;
8
9 namespace CodeFirstAppDemo
10 {
11 class Program
12 {
13 static void Main(string[] args)
14 {
15 // 使用資料庫上下文Context
16 using (var context = new Context())
17 {
18 // 如果資料庫不存在,則呼叫EF內建的API建立資料庫
19 if (context.Database.CreateIfNotExists())
20 {
21 Console.WriteLine("資料庫建立成功!");
22 }
23 else
24 {
25 Console.WriteLine("資料庫已存在");
26 }
27
28 #region EF 刪除資料
29
30 var products = context.Products;
31 // 先根據ProductName找到要刪除的元素
32 var toDeleteProduct = context.Products.Single(p => p.ProductName == "唐詩三百首");
33 if (toDeleteProduct != null)
34 {
35 // 方式1:使用Remove()方法移除
36 context.Products.Remove(toDeleteProduct);
37 // 方式2:更改資料的狀態
38 context.Entry(toDeleteProduct).State = EntityState.Deleted;
39 // 最後持久化到資料庫
40 context.SaveChanges();
41
42 #endregion
43 }
44
45 Console.ReadKey();
46 }
47 }
48 }