使用EF的Code?First模式操作數(shù)據(jù)庫
EF的核心程序集位于System.Data.Entity.dll和System.Data.EntityFramework.dll中。
支持CodeFirst的位于EntityFramework.dll中。
通常使用NuGet Package Manager來添加這些程序集。
如果沒有數(shù)據(jù)庫:
- 1、先寫代碼,自動(dòng)創(chuàng)建數(shù)據(jù)庫。
- 2、如果代碼有變化,自動(dòng)刪除數(shù)據(jù)庫重建,或者是使用遷移功能更改已有數(shù)據(jù)庫。
如果已有數(shù)據(jù)庫:
- 使用EF PowerTools反向工程生成模型。
下面的示例程序中將通過一個(gè)控制臺(tái)程序演示如何通過Code First模式創(chuàng)建一個(gè)數(shù)據(jù)庫,并執(zhí)行簡單的增刪改查操作。
一、創(chuàng)建一個(gè)控制臺(tái)應(yīng)用程序,命名為CodeFirstAppDemo。
二、安裝Entity Framework,添加對Code First的支持
1、通過Nuget包管理器控制臺(tái)進(jìn)行安裝
選擇“工具”->Nuget程序包管理器->程序包管理器控制臺(tái),下面將會(huì)打開程序包管理器控制臺(tái)窗口:
輸入命令:Install-Package EntityFramework進(jìn)行安裝。
2、通過可視化界面進(jìn)行安裝
在項(xiàng)目上面右鍵選擇管理Nuget程序包:
選擇EntityFramework,點(diǎn)擊“安裝”按鈕進(jìn)行安裝:
安裝完以后,項(xiàng)目引用里面將會(huì)出現(xiàn)EntityFramework程序集:
如果安裝完以后,項(xiàng)目引用里面沒有這兩個(gè)dll,一定要檢查為什么沒有安裝成功,因?yàn)橄旅娴某绦蛑幸玫紻bContext類,該類位于EntityFramework程序集中。
三、根據(jù).NET中的類來創(chuàng)建數(shù)據(jù)庫。
經(jīng)過上面的步驟之后,我們就可以開始寫代碼了。在寫代碼之前,要始終記得:每個(gè)實(shí)體類就是相應(yīng)的數(shù)據(jù)表中的一行數(shù)據(jù),該實(shí)體類的屬性對應(yīng)的就是數(shù)據(jù)表中的列。
1、創(chuàng)建EDM實(shí)體數(shù)據(jù)模型
在項(xiàng)目上右鍵->添加->新建文件夾,命名為Models,存放相應(yīng)的實(shí)體類。在Models文件夾下面新建兩個(gè)實(shí)體類:Category和Product,Category里面包含一個(gè)類型是Product的集合屬性,兩個(gè)實(shí)體類的屬性分別如下:
Category類:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace CodeFirstAppDemo.Models { /// <summary> /// 產(chǎn)品分類表 /// </summary> public class Category { /// <summary> /// 分類ID /// </summary> public int CategoryId { get; set; } /// <summary> /// 分類名稱 /// </summary> public string CategoryName { get; set; } /// <summary> /// 產(chǎn)品 /// </summary> public List<Product> ProductList { get; set; } } }
Produce類:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace CodeFirstAppDemo.Models { /// <summary> /// 產(chǎn)品類 /// </summary> public class Product { /// <summary> /// 產(chǎn)品Id /// </summary> public int Id { get; set; } /// <summary> /// 產(chǎn)品名稱 /// </summary> public string ProductName { get; set; } /// <summary> /// 產(chǎn)品價(jià)格 /// </summary> public decimal Price { get; set; } /// <summary> /// 出版日期 /// </summary> public DateTime PublicDate { get; set; } } }
我們需要定義和期望的數(shù)據(jù)庫類型相匹配的屬性。上面的例子中,.Net中的int類型會(huì)映射到SQL Server中的int類型,string類型會(huì)映射到所有可能的字符類型,decimal和Datetime也和SQL Server中的一樣。大多數(shù)時(shí)候,我們不需要關(guān)心這些細(xì)節(jié),我們只需要編寫能夠表示數(shù)據(jù)的模型類就行了,然后使用標(biāo)準(zhǔn)的.Net類型定義屬性,其他的就讓EF自己計(jì)算出保存數(shù)據(jù)所需要的RDBMS類型。
2、創(chuàng)建數(shù)據(jù)上下文
接下來我們創(chuàng)建數(shù)據(jù)庫上下文,它是數(shù)據(jù)庫的抽象。目前,我們有兩張張表Category和Product,因而要給該數(shù)據(jù)庫上下文定義兩個(gè)屬性來代表這兩張表。再者,一張表中一般肯定不止一條數(shù)據(jù)行,所以我們必須定義一個(gè)集合屬性,EF使用DbSet來實(shí)現(xiàn)這個(gè)目的。
在項(xiàng)目上右鍵->添加->新建文件夾,命名為EFDbContext,用來存放數(shù)據(jù)庫上下文類。添加類Context,并使該類繼承自DbContext類。DbContext位于EntityFramework.dll程序集中。
Context類代碼如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Data.Entity; using CodeFirstAppDemo.Models; namespace CodeFirstAppDemo.EFDbContext { public class Context : DbContext { /// <summary> /// 1、創(chuàng)建構(gòu)造函數(shù),構(gòu)造函數(shù)繼承DbContext類的構(gòu)造函數(shù),通過DbContext類的構(gòu)造函數(shù)創(chuàng)建數(shù)據(jù)庫連接 /// 2、DbContext類的構(gòu)造函數(shù)里面的參數(shù)是數(shù)據(jù)庫連接字符串,通過該連接字符串去創(chuàng)建數(shù)據(jù)庫 /// </summary> public Context() : base("name=FirstCodeFirstApp") { } //2、定義數(shù)據(jù)集合:用于創(chuàng)建表 public DbSet<Category> Categorys { get; set; } public DbSet<Product> Products { get; set; } } }
在這里,DbContext是所有基于EF的上下文基類,通過它可以訪問到數(shù)據(jù)庫中的所有表。上面的代碼中調(diào)用了父類的構(gòu)造函數(shù),并且傳入了一個(gè)鍵值對,鍵是name,值是CodeFirstApp,這個(gè)鍵值對是定義在應(yīng)用程序的配置文件中的,取決于你的應(yīng)用程序類型,可能是app.config或者web.config。在我們的控制臺(tái)應(yīng)用程序中就是app.config。
在app.config文件的configuration節(jié)點(diǎn)下(不要在第一個(gè)節(jié)點(diǎn)下,否則會(huì)報(bào)錯(cuò))添加:
<connectionStrings> <add name="CodeFirstApp" connectionString="Server=.;Database=CodeFirstApp;User Id=sa;Password=test" providerName="System.Data.SqlClient"/> </connectionStrings>
3、使用EF提供的API訪問數(shù)據(jù)庫來創(chuàng)建數(shù)據(jù)庫
using CodeFirstAppDemo.EFDbContext; using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace CodeFirstAppDemo { class Program { static void Main(string[] args) { // 使用數(shù)據(jù)庫上下文Context using (var context = new Context()) { // 如果數(shù)據(jù)庫不存在,則調(diào)用EF內(nèi)置的API創(chuàng)建數(shù)據(jù)庫 if (context.Database.CreateIfNotExists()) { Console.WriteLine("數(shù)據(jù)庫創(chuàng)建成功!"); } else { Console.WriteLine("數(shù)據(jù)庫已存在"); } } Console.ReadKey(); } } }
最后,只需要確保連接字符串沒有問題就可以了。運(yùn)行程序,然后打開SSMS進(jìn)行確認(rèn)數(shù)據(jù)庫是否創(chuàng)建成功即可。
這時(shí)可以清楚地看到,數(shù)據(jù)庫表名是自定義數(shù)據(jù)庫上下文中DbSet<T>屬性中T類型的復(fù)數(shù)形式。例如T類型是Product,那么生成的表名就是Products,而表中的列是數(shù)據(jù)模型的屬性。此外,注意以下列的類型。EF默認(rèn)將id作為了主鍵,string類型的ProductName在數(shù)據(jù)庫中的類型是nvarchar(max),這些都是在使用EF時(shí)必須注意的命名規(guī)格。
四、執(zhí)行簡單的CRUD操作
1、創(chuàng)建記錄-Create
你可以這樣認(rèn)為,將對象添加到集合中就相當(dāng)于將數(shù)據(jù)插入到數(shù)據(jù)庫相應(yīng)的表中。我們使用DbSet的Add方法來實(shí)現(xiàn)新數(shù)據(jù)的添加,而DbContext類的SaveChanges方法會(huì)將未處理的更改提交到數(shù)據(jù)庫,這是通過檢測上下文中所有的對象的狀態(tài)來完成的。所有的對象都駐留在上下文類的DbSet屬性中。比如,例子中有一個(gè)Products屬性,那么所有的產(chǎn)品數(shù)據(jù)都會(huì)存儲(chǔ)到這個(gè)泛型集合屬性中。數(shù)據(jù)庫上下文會(huì)跟蹤DbSet屬性中的所有對象的狀態(tài),這些狀態(tài)有這么幾種:Deleted、Added、Modified和Unchanged。如果你想在一個(gè)表中插入多行數(shù)據(jù),那么只需要添加該表對應(yīng)的類的多個(gè)對象的實(shí)例即可,然后使用SaveChanges方法將更改提交到數(shù)據(jù)庫,該方法是以單事務(wù)執(zhí)行的。最終,所有的數(shù)據(jù)庫更改都會(huì)以單個(gè)工作單元持久化。既然是事務(wù),那么就允許將批量相關(guān)的更改作為單個(gè)操作提交,這樣就保證了事務(wù)一致性和數(shù)據(jù)完整性。
修改Main方法如下:
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) { // 使用數(shù)據(jù)庫上下文Context using (var context = new Context()) { // 如果數(shù)據(jù)庫不存在,則調(diào)用EF內(nèi)置的API創(chuàng)建數(shù)據(jù)庫 if (context.Database.CreateIfNotExists()) { Console.WriteLine("數(shù)據(jù)庫創(chuàng)建成功!"); } else { Console.WriteLine("數(shù)據(jù)庫已存在"); } #region EF 添加數(shù)據(jù) //添加數(shù)據(jù) var cate = new List<Category> { new Category{ CategoryName="文學(xué)類", ProductList=new List<Product>{ new Product { ProductName="百年孤獨(dú)", Price=37.53m, PublicDate=new DateTime(2011,6,1) }, new Product { ProductName="老人與海", Price=37.53m, PublicDate=new DateTime(2010,6,1) } } }, new Category{ CategoryName="計(jì)算機(jī)類", ProductList=new List<Product>{ new Product { ProductName="C#高級編程第九版", Price=48.23m, PublicDate=new DateTime(2016,2,8) }, new Product { ProductName="Oracle從入門到精通", Price=27.03m, PublicDate=new DateTime(2014,7,9) } } } }; //將創(chuàng)建的集合添加到上下文中 context.Categorys.AddRange(cate); //調(diào)用SaveChanges()方法,將數(shù)據(jù)插入到數(shù)據(jù)庫 context.SaveChanges(); #endregion } Console.ReadKey(); } } }
這里需要注意兩點(diǎn):
1、不需要給Product.Id屬性賦值,因?yàn)樗鼘?yīng)到SQL Server表中的主鍵列,它的值是自動(dòng)生成的,當(dāng)SaveChanges執(zhí)行以后,打斷點(diǎn)就能看到返回的Product.Id已經(jīng)有值了。
2、Context的實(shí)例用了using語句包裝起來,這是因?yàn)镈bContext實(shí)現(xiàn)了IDisposable接口。DbContext還包含了DbConnection的實(shí)例,該實(shí)例指向了具有特定連接字符串的數(shù)據(jù)庫。在EF中合適地釋放數(shù)據(jù)庫連接和ADO.NET中同等重要。
2、查詢記錄-Retrieve
查詢時(shí)也是直接通過DbSet進(jìn)行查詢的:
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) { // 使用數(shù)據(jù)庫上下文Context using (var context = new Context()) { // 如果數(shù)據(jù)庫不存在,則調(diào)用EF內(nèi)置的API創(chuàng)建數(shù)據(jù)庫 if (context.Database.CreateIfNotExists()) { Console.WriteLine("數(shù)據(jù)庫創(chuàng)建成功!"); } else { Console.WriteLine("數(shù)據(jù)庫已存在"); } #region EF 2查詢數(shù)據(jù) //查詢方式1 var products = from p in context.Categorys select p; foreach (var item in products) { Console.WriteLine("分類名稱:" + item.CategoryName); } //查詢方式2 //延遲加載 cates里面沒有數(shù)據(jù) var cates = context.Categorys; //執(zhí)行迭代的時(shí)候才有數(shù)據(jù) foreach (var item in cates) { Console.WriteLine("分類名稱:" + item.CategoryName); } #endregion } Console.ReadKey(); } } }
如果像下面那樣打一個(gè)斷點(diǎn),你會(huì)看到一個(gè)結(jié)果視圖,點(diǎn)擊類似刷新的圖標(biāo)會(huì)看到查詢的結(jié)果,這個(gè)東西道出了EF中很重要的一個(gè)概念:延遲加載。此時(shí)還沒有真正查詢數(shù)據(jù)庫,只有當(dāng)LINQ的查詢結(jié)果被訪問或者被枚舉時(shí)才會(huì)將查詢命令發(fā)送到數(shù)據(jù)庫。EF是基于DbSet實(shí)現(xiàn)的IQueryable接口來處理延遲查詢的。
3、更新記錄-Update
在SQL中,更新需要執(zhí)行Update命令。而在EF中,我們要找到DbSet實(shí)體集合中要更新的對象,然后修改其屬性,最后調(diào)用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) { // 使用數(shù)據(jù)庫上下文Context using (var context = new Context()) { // 如果數(shù)據(jù)庫不存在,則調(diào)用EF內(nèi)置的API創(chuàng)建數(shù)據(jù)庫 if (context.Database.CreateIfNotExists()) { Console.WriteLine("數(shù)據(jù)庫創(chuàng)建成功!"); } else { Console.WriteLine("數(shù)據(jù)庫已存在"); } #region EF 更新數(shù)據(jù) var products = context.Products; if (products.Any()) { // 查詢產(chǎn)品名稱是“百年孤獨(dú)”的產(chǎn)品 var toUpdateProduct = products.First(p => p.ProductName == "百年孤獨(dú)"); // 修改查詢出的產(chǎn)品名稱 toUpdateProduct.ProductName = "唐詩三百首"; // 調(diào)用SaveChanges()方法保存數(shù)據(jù) context.SaveChanges(); } #endregion } Console.ReadKey(); } } }
這里我們使用了Any()擴(kuò)展方法來判斷序列中是否有元素,然后使用First()擴(kuò)展方法來找到Name=="百年孤獨(dú)"的元素,然后給目標(biāo)對象的Name屬性賦予新值,最后調(diào)用SaveChanges()方法保存數(shù)據(jù)。
4、刪除記錄-Delete
要?jiǎng)h除一條數(shù)據(jù),就要先找到這條數(shù)據(jù).
using CodeFirstAppDemo.EFDbContext; using CodeFirstAppDemo.Models; using System; using System.Collections.Generic; using System.Data.Entity; using System.Linq; using System.Text; namespace CodeFirstAppDemo { class Program { static void Main(string[] args) { // 使用數(shù)據(jù)庫上下文Context using (var context = new Context()) { // 如果數(shù)據(jù)庫不存在,則調(diào)用EF內(nèi)置的API創(chuàng)建數(shù)據(jù)庫 if (context.Database.CreateIfNotExists()) { Console.WriteLine("數(shù)據(jù)庫創(chuàng)建成功!"); } else { Console.WriteLine("數(shù)據(jù)庫已存在"); } #region EF 刪除數(shù)據(jù) var products = context.Products; // 先根據(jù)ProductName找到要?jiǎng)h除的元素 var toDeleteProduct = context.Products.Single(p => p.ProductName == "唐詩三百首"); if (toDeleteProduct != null) { // 方式1:使用Remove()方法移除 context.Products.Remove(toDeleteProduct); // 方式2:更改數(shù)據(jù)的狀態(tài) context.Entry(toDeleteProduct).State = EntityState.Deleted; // 最后持久化到數(shù)據(jù)庫 context.SaveChanges(); #endregion } Console.ReadKey(); } } }
到此這篇關(guān)于使用EF的Code First模式操作數(shù)據(jù)庫的文章就介紹到這了。希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
asp.net core常見的4種數(shù)據(jù)加密算法
這篇文章主要介紹了asp.net core常見的4種數(shù)據(jù)加密算法,文中代碼非常詳細(xì),幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下2020-06-06利用ASP.NET MVC+Bootstrap搭建個(gè)人博客之打造清新分頁Helper(三)
這篇文章主要介紹了利用ASP.NET MVC+Bootstrap搭建個(gè)人博客之打造清新分頁Helper(三)的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-06-06總結(jié)Visual Studio下ASP.NET模板化控件中的數(shù)據(jù)綁定
.NET框架中提供了很多數(shù)據(jù)綁定的組件,這里我們就來總結(jié)Visual Studio下ASP.NET模板化控件中的數(shù)據(jù)綁定,需要的朋友可以參考下2016-06-06asp.net實(shí)現(xiàn)存儲(chǔ)和讀取數(shù)據(jù)庫圖片
這篇文章主要為大家詳細(xì)介紹了asp.net實(shí)現(xiàn)存儲(chǔ)和讀取數(shù)據(jù)庫圖片,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-11-11asp.net 在處理向該請求提供服務(wù)所需的配置文件時(shí)出錯(cuò)
遭遇:“說明: 在處理向該請求提供服務(wù)所需的配置文件時(shí)出錯(cuò)。請檢查下面的特定錯(cuò)誤詳細(xì)信息并適當(dāng)?shù)匦薷呐渲梦募!卞e(cuò)誤2010-03-03