EF也是一種ORM技術框架, 將對象模型和關係型數據庫的數據結構對應起來,開發人員不在利用sql去操做數據相關結構和數據。
如下是EF創建的數據庫和對象之間關係sql
關係數據庫
|
對象
|
數據庫
|
DbContext類
|
表
|
DbContext中的DbSet<實體類名>
|
表間的關聯
|
實體類之間的關聯
|
字段
|
實體類的公有屬性
|
單條數據
|
單個實體類的對象
|
約束(主鍵、外鍵默認值)
|
實體類中的特性
|
EF使用概念模型、 映射和存儲模型。三個模型來描述映射關係數據庫
public class Place { [Key] public int PlaceID { get; set;} public string Provice { get; set; } public string City { get; set; } //導航屬性 public List<People> Population { get; set; } }
public class People { [Key] public int PeopleID{ get; set; } public string Name{ get; set; } public int Age{ get; set;} //外鍵,對應導航屬性對象中的標識 [ForeignKey("Place")] public int PlaceID{ get; set;} //導航屬性 public Place Place { get; set; } }
public class TestDB:DbContext { public TestDB():base("name=Test") { } public DbSet<Place> Place { get; set; } public DbSet<People> People { get; set; } }
class Program { static void Main(string[] args) { using (var context = new TestDB()) { context.Place.Add(new Place { PlaceID = 2, Provice="jiangsu", City="wuxi" }); context.SaveChanges(); } } }
發如今數據庫已經建好了相應的表,這時在people類增長Sex屬性,隨便增長一條數據執行代碼,報了以下錯,很顯然EF並不會幫咱們更新數據庫結構:緩存
有兩種狀況處理這種狀況,手動和自動遷移方式去更新數據庫數據結構
一、選擇所在的項目,在VS的程序包管理控制檯輸入命令(Tools菜單中打開Package Manager Console):框架
enable-migrations –EnableAutomaticMigrations
二、執行完畢,項目目錄中多出一個名爲Migrations的文件夾,裏面有個Configuration.cs文件,打開它看到以下代碼:數據庫設計
internal sealed class Configuration : DbMigrationsConfiguration<EF1.Model.TestDB> { public Configuration() { AutomaticMigrationsEnabled = true; ContextKey = "EF1.Model.TestDB"; } protected override void Seed(EF1.Model.TestDB context) { // This method will be called after migrating to the latest version. // You can use the DbSet<T>.AddOrUpdate() helper extension method // to avoid creating duplicate seed data. } }
ContextKey屬性指定了要執行遷移的DbContext,以便多個DbContext共存遷移不會產生衝突。ide
在遷移過程成功後會執行Seed方法,能夠利用這個方法添加一些初始化數據函數
在刪除屬性的時候,會遷移失敗,提示操做會形成數據丟失,能夠在構造函數中添加以下代碼,忽略數據丟失。學習
public Configuration() { AutomaticMigrationsEnabled = true; AutomaticMigrationDataLossAllowed = true; ContextKey = "EF1.Model.TestDB"; }
3.以上步驟已開啓支持遷移,每次更新實體結構時,在項目執行前,須要在管理控制檯輸入如下命令先更新數據庫spa
update-database
或是在DbContext構造函數中添加如下代碼,每次將自動遷移至最新的數據庫Schema
public class TestDB:DbContext { public TestDB():base("name=Test") { //TestDB:dbContext;
//Test:鏈接字符串名稱 //遷移至最新版本 Database.SetInitializer(new MigrateDatabaseToLatestVersion<TestDB, Configuration>("Test")); } public DbSet<Place> Place { get; set; } public DbSet<People> People { get; set; } }
兩種遷移方式基本相同,只是相比自動遷移,手動遷移會記錄每次更新的狀況,容許回滾數據庫到某個指定版本,適合於團隊開發。
1.同樣要先開啓支持遷移,並吧生成的Configuration構造函數中AutomaticMigrationsEnabled置爲false,表示不使用自動遷移。
2.每次更改實體結構或映射配置時,在程序包管理控制檯運行如下代碼
Add-Migration ChangeSet1
會自動在前面生成的Migrations文件下生成一個ChangeSet1遷移文件
類的內容就是對於咱們所更改的實體結構或映射配置,EF遷移要執行的內容,如下就是我增長了一個Phone屬性,運行Add-Migration ChangeSet1所生成的。此遷移文件後面能夠用來回滾到某個版本
public partial class ChangeSet1 : DbMigration { public override void Up() { AddColumn("dbo.People", "Phone", c => c.String()); } public override void Down() { DropColumn("dbo.People", "Phone"); } }
3.成功遷移文件後,運行下面代碼更新至最新的遷移文件對應的版本。
Update-Database
或是回滾到指定版本
Update-Database -TargetMigration ChangeSet1
上下文是根據檢測實體的EntityState枚舉狀態,來執行相應的增/刪/改操做。
EntityState枚舉狀態以下:
DBcontext類中的方法:
DbSet類
基本方式
static void Main(string[] args) { using (var context = new TestDB()) { context.Place.Add(new Place { PlaceID = 8, Provice = "jiangsu", City = "wuxi", }); context.SaveChanges(); } }
Entry方式
附:用attch附加到上下文保存無效,由於附加後的狀態是unchange,須要使用ChangeObjectState方法更改實體狀態,或是再次使用Entry獲取狀態管理對象更新
static void Main(string[] args) { using (var context = new TestDB()) { var obj = new Place() { PlaceID =9, Provice = "jiangsu", City = "wuxi", }; //加入EF容器,並獲取當前實體對象的狀態管理對象 var entity = context.Entry<Place>(obj); entity.State = System.Data.Entity.EntityState.Added; context.SaveChanges(); } }
先查詢後更新:
static void Main(string[] args) { using (var context = new TestDB()) { var query = context.Place.Where(p => p.PlaceID == 9).FirstOrDefault(); query.City = "suzhou"; context.SaveChanges(); } }
Entry
using (var context = new TestDB()) { var obj = new Place { PlaceID=9, City="changzhou" }; //將obj加入到上下文,並去獲取實體對象的狀態管理對象 var entity = context.Entry<Place>(obj); //置爲未被修改過 entity.State = System.Data.Entity.EntityState.Unchanged; //設置該對象的City屬性爲修改狀態,同時 entity.State由Unchanged-> Modified 狀態 entity.Property("City").IsModified = true; context.SaveChanges(); }
Attach
using (var context = new TestDB()) { var obj = new Place { PlaceID=9 }; //將obj附加到上下文,此時實體狀態爲Unchanged var newobj=context.Place.Attach(obj); //這時City屬性爲修改狀態,同時entity.State自動由Unchanged-> Modified 狀態 newobj.City = "yangzhou"; context.SaveChanges(); }
常規操做:先查詢後刪除
using (var context = new TestDB()) { var queryObj = context.Place.Where(q=>q.PlaceID==8).FirstOrDefault(); //當前的實體對象已置爲Deleted狀態 context.Place.Remove(queryObj); context.SaveChanges(); }
Entry
using (var context = new TestDB()) { var obj = new Place { PlaceID = 6 }; //將obj附加到上下文,並獲取實體對象的狀態管理對象 var entity =context.Entry<Place>(obj); //將狀態置爲Deleted entity.State = System.Data.Entity.EntityState.Deleted; context.SaveChanges(); }
Attach
using (var context = new TestDB()) { var obj = new Place { PlaceID = 7 }; //將obj附加到上下文,此時實體狀態爲Unchanged var newobj = context.Place.Attach(obj); context.Place.Remove(newobj); context.SaveChanges(); }
對於簡單查詢,不須要進行修改操做,建議使用AsNoTracking,無跟蹤查詢來提高效率
using (var context = new TestDB()) { var obj = context.Place.Where(p => p.PlaceID == 9).AsNoTracking().ToList(); }
Find方法 :以前一直使用lambda查詢(where,FirstOrDefault),有一個問題就是無論咱們要查詢的實體是否被dbconext緩存,都會去查詢數據庫,而使用Find經過主鍵來查詢,會首先在EF Context中查找是否有被緩存過的實體,若是查找不到纔去數據庫查找
using (var context = new TestDB()) { var obj = context.Place.Find(9); }
注:更詳細的EF查詢學習會在查漏補缺(二) 數據加載 中繼續記錄