EF應用一:Code First模式


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 }

 


免責聲明!

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



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