一、 EntirtyFramework(EF)簡介
EntirtyFramework框架是一個輕量級的可擴展版本的流行實體框架數據訪問技術,微軟官方提供的ORM工具讓開發人員節省數據庫訪問的代碼時間,將更多的時間放到業務邏輯層代碼上。EF提供變更跟蹤、唯一性約束、惰性加載、查詢事物等。開發人員使用Linq語言,對數據庫操作如同操作Object對象一樣省事。
EF有三種使用場景,1. 從數據庫生成Class(DB First),2.由實體類生成數據庫表結構(Code First),3. 通過數據庫可視化設計器設計數據庫,同時生成實體類(Model First)。
EF架構如下:
EDM (實體數據模型):EDM包括三個模型,概念模型、 映射和存儲模型。
概念模型 ︰ 概念模型包含模型類和它們之間的關系。獨立於數據庫表的設計。
存儲模型 ︰ 存儲模型是數據庫設計模型,包括表、 視圖、 存儲的過程和他們的關系和鍵。
映射 ︰ 映射包含有關如何將概念模型映射到存儲模型的信息。
LINQ to Entities ︰ LINQ to Entities 是一種用於編寫針對對象模型的查詢的查詢語言。它返回在概念模型中定義的實體。
Entity SQL: Entity SQL 是另一種爐類似於L2E的言語,但相給L2E要復雜的多,所以開發人員不得不單獨學習它。
Object Services(對象服務):是數據庫的訪問入口,負責數據具體化,從客戶端實體數據到數據庫記錄以及從數據庫記錄和實體數據的轉換。
Entity Client Data Provider:主要職責是將L2E或Entity Sql轉換成數據庫可以識別的Sql查詢語句,它使用Ado.net通信向數據庫發送數據可獲取數據。
ADO.Net Data Provider:使用標准的Ado.net與數據庫通信。
二、EntirtyFrameworkCore(EF Core)
Entity Framework Core (EF Core) 是在 2016 年首次發布的 EF6 的完全重寫。 它附帶於 Nuget 包中,是 Microsoft.EntityFrameworkCore 的主要組成部分。 EF Core 是一種跨平台產品,可以在 .NET Core 或 .NET Framework 上運行。EF Core 提供了在 EF6 中不會實現的新功能(如備選鍵、批量更新以及 LINQ 查詢中的混合客戶端/數據庫評估。但由於它是一個新代碼庫,所以會缺少一些 EF6 中的功能。
EFCore與之前的EF基本類似,區別在於配置的時候有一些差異;支持DB First和Model First,廣泛使用的Code First模式;EF Core2.1開始支持Lazy loading。
EFCore的數據庫訪問技術使用之前請先安裝Microsoft.EntityFrameworkCore包
三、EF Core使用DB First
數據庫優先(DB First),編碼步驟如下:
1、新建數據庫
2、對模型實施反向工程
Scaffold-DbContext [-Connection] <String> [-Provider] <String> [-OutputDir <String>] [-Context <String>]
[-Schemas <String>] [-Tables <String>] [-DataAnnotations] [ -Force] [-Project <String>]
[-StartupProject <String>] [-Environment <String>] [<CommonParameters>]
3、在項目中配置數據庫連接字符串。
四、EF Core使用Code First
編碼優先(Code First),執行步驟如下:
1、新建模型類
2、新建DBContext
3、在項目中配置數據庫連接字符串
4、執行如下命令(數據庫遷移): Add-Migration [類名], Update-Database
數據表級聯,這里主要說一下級聯刪除
1、外鍵屬性可為NULL的級聯刪除時外鍵屬性直接設置為 null即可
2、外鍵屬性不可為NULL級聯刪除時會引發異常,需要設置刪除行為 DeleteBehavior ,DeleteBehavior 的類型如下表所示
數據加載是需要重點掌握的,EF的關聯實體加載有三種方式:Lazy Loading,Eager Loading,Explicit Loading,其中Lazy Loading和Explicit Loading都是延遲加載。
(一)Lazy Loading(惰性加載)使用的是動態代理,默認情況下,如果POCO類滿足以下兩個條件,EF就使用Lazy Loading:
POCO類是Public且不為Sealed。導航屬性標記為Virtual。
關閉Lazy Loading,可以將LazyLoadingEnabled設為false,如果導航屬性沒有標記為virtual,Lazy Loading也是不起作用的。

1 /// <summary>
2 /// 用戶信息表 3 /// </summary>
4 public class User 5 { 6 /// <summary>
7 /// 用戶ID 8 /// </summary>
9 //[Key] 10 //[DatabaseGenerated(DatabaseGeneratedOption.Identity)] //設置自增
11 public int UserId { get; set; } 12 /// <summary>
13 /// 用戶編碼 14 /// </summary>
15 public string UserNo { get; set; } 16 /// <summary>
17 /// 用戶名稱 18 /// </summary>
19 public string UserName { get; set; } 20 /// <summary>
21 /// 用戶電話 22 /// </summary>
23 public string TelPhone { get; set; } 24 /// <summary>
25 /// 備注 26 /// </summary>
27 public string Remark { get; set; } 28 public virtual Orginazation Org { get; set; } 29 public virtual ICollection<UserAndRole> Roles { get; set; } 30 }

1 /// <summary>
2 /// 角色信息表 3 /// </summary>
4 public class Role 5 { 6 /// <summary>
7 /// 角色ID 8 /// </summary>
9 //[Key] 10 //[DatabaseGenerated(DatabaseGeneratedOption.Identity)] //設置自增
11 public int RoleID { get; set; } 12 /// <summary>
13 /// 角色編碼 14 /// </summary>
15 public string RoleNO { get; set; } 16 /// <summary>
17 /// 角色名稱 18 /// </summary>
19 public string RoleName { get; set; } 20 /// <summary>
21 /// 備注 22 /// </summary>
23 public string Remark { get; set; } 24 public virtual ICollection<UserAndRole> Users { get; set; } 25 }

1 /// <summary>
2 /// 部門信息表 3 /// </summary>
4 public class Orginazation 5 { 6 //private readonly ILazyLoader _lazyLoader; 7
8 //public Orginazation(ILazyLoader lazyLoader) 9 //{ 10 // _lazyLoader = lazyLoader; 11 //}
12
13 /// <summary>
14 /// 部門ID 15 /// </summary>
16 [Key] 17 [DatabaseGenerated(DatabaseGeneratedOption.Identity)] //設置自增
18 public int OrgId { get; set; } 19 /// <summary>
20 /// 部門編碼 21 /// </summary>
22 public string OrgNO { get; set; } 23 /// <summary>
24 /// 部門名稱 25 /// </summary>
26 public string OrgName { get; set; } 27 /// <summary>
28 /// 備注 29 /// </summary>
30 public string Remark { get; set; } 31 public virtual ICollection<User> Users { get; set; } 32 }

在.net Core2.0及以上版本中使用惰性加載需要引用惰性加載代理包,EF Core一般情況下使用惰性加載,因此為了避免報循環引用的異常需要設置ReferenceLoopHandling為Ignore
Install-package Microsoft.EntityFrameworkCore.Proxies
Startup.cs文件顯示使用惰性加載

public void ConfigureServices(IServiceCollection services) { services.Configure<CookiePolicyOptions>(options => { // This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true; options.MinimumSameSitePolicy = SameSiteMode.None; }); services.AddDbContext<CodeFirstContext>(options => { //注入數據庫
options.UseSqlServer(Configuration.GetConnectionString("SqlServerConnStr")).ToString(); //打開延遲加載代理的創建。
options.UseLazyLoadingProxies(); }); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1).AddJsonOptions(options => { //由於使用了惰性加載,因此需要設置此參數避免報循壞引用的異常
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; }); }

1 public class HomeController : Controller 2 { 3 private readonly CodeFirstContext _dbContext; 4 public IConfiguration Configuration { get; } 5 string conn = string.Empty; 6 public HomeController(CodeFirstContext _context) 7 { 8 _dbContext = _context; 9 } 10 public IActionResult Index() 11 { 12 Role role = new Role 13 { 14 RoleNO = "0001", 15 RoleName = "管理員角色", 16 Remark = "所有權限"
17 }; 18 Orginazation org = new Orginazation 19 { 20 OrgNO = "00001", 21 OrgName = "總公司", 22 Remark = "部門根節點"
23 }; 24 User user = new User 25 { 26 UserNo = "admin", 27 UserName = "管理員", 28 Remark = "系統管理員", 29 TelPhone="22342432", 30 Org = org 31 }; 32 UserAndRole userAndRoleModel = new UserAndRole 33 { 34 Role = role, 35 User = user, 36 RoleID = role.RoleID, 37 UserId = user.UserId 38 }; 39 user.Roles.Add(userAndRoleModel); 40 role.Users.Add(userAndRoleModel); 41 _dbContext.Roles.Add(role); 42 _dbContext.Orginazations.Add(org); 43 _dbContext.Users.Add(user); 44 _dbContext.UserAndRoles.Add(userAndRoleModel); 45
46
47 _dbContext.SaveChanges(); 48
49 //延遲加載
50 var orgs = _dbContext.Orginazations; 51 foreach (var userModel in orgs.FirstOrDefault().Users) 52 { 53 //刪除部門用戶
54 _dbContext.Users.Remove(userModel); 55 } 56 _dbContext.SaveChanges(); 57 return View(); 58 } 59
60 public IActionResult About() 61 { 62 _dbContext.Roles.Add(new Role 63 { 64 RoleNO = "role1", 65 RoleName = "RoleName1", 66 Remark = "Remark1"
67 }); 68
69 //刪除用戶,對應頭像表里的數據也會被刪除
70 var user = _dbContext.Users.First(); 71 _dbContext.Users.Remove(user); 72 _dbContext.SaveChanges(); 73
74 ViewData["Message"] = "Your application description page."; 75
76 return View(); 77 } 78
79 public IActionResult Contact() 80 { 81 ViewData["Message"] = "Your contact page."; 82
83 return View(); 84 } 85
86 public IActionResult Privacy() 87 { 88 return View(); 89 } 90
91 [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] 92 public IActionResult Error() 93 { 94 return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier }); 95 } 96 }

1 /// <summary>
2 /// Code First編碼上下文 3 /// </summary>
4 public class CodeFirstContext : DbContext 5 { 6 public CodeFirstContext(DbContextOptions<CodeFirstContext> conn) 7 : base(conn) 8 { 9 } 10 /// <summary>
11 /// 映射用戶信息表 12 /// </summary>
13 public virtual DbSet<User> Users { get; set; } 14 /// <summary>
15 /// 映射部門信息表 16 /// </summary>
17 public virtual DbSet<Orginazation> Orginazations { get; set; } 18 /// <summary>
19 /// 映射角色信息表 20 /// </summary>
21 public virtual DbSet<Role> Roles { get; set; } 22 /// <summary>
23 /// 用戶角色信息表 24 /// </summary>
25 public virtual DbSet<UserAndRole> UserAndRoles { get; set; } 26 protected override void OnModelCreating(ModelBuilder modelBuilder) 27 { 28 //用戶
29 modelBuilder.Entity<User>(entity =>
30 { 31 entity.ToTable("User"); 32 entity.Property(e => e.UserName).IsRequired().HasMaxLength(64); 33 entity.Property(e => e.UserNo).IsRequired().HasMaxLength(64); 34 entity.Property(e => e.TelPhone).HasMaxLength(64); 35 entity.Property(e => e.Remark).HasMaxLength(256); 36 entity.HasOne(u => u.Org).WithMany(r => r.Users).OnDelete(DeleteBehavior.SetNull); 37
38 }); 39
40 //角色
41 modelBuilder.Entity<Role>(entity =>
42 { 43 entity.ToTable("Role"); 44 entity.Property(e => e.RoleName).IsRequired().HasMaxLength(64); 45 entity.Property(e => e.RoleNO).IsRequired().HasMaxLength(64); 46 entity.Property(e => e.Remark).HasMaxLength(256); 47 }); 48
49 //部門信息
50 modelBuilder.Entity<Orginazation>(entity =>
51 { 52 entity.ToTable("Orginazation"); 53 entity.Property(e => e.OrgNO).IsRequired().HasMaxLength(64); 54 entity.Property(e => e.OrgName).IsRequired().HasMaxLength(64); 55 entity.Property(e => e.Remark).HasMaxLength(256); 56 //多個用戶對應一個部門
57 entity.HasMany(u => u.Users).WithOne(r => r.Org).OnDelete(DeleteBehavior.SetNull); 58 }); 59
60 //用戶角色信息表
61 modelBuilder.Entity<UserAndRole>(entity =>
62 { 63 entity.ToTable("UserAndRole"); 64 entity.HasKey(ua => new { ua.RoleID, ua.UserId }); 65 }); 66 modelBuilder.Entity<UserAndRole>(entity =>
67 { 68 entity.ToTable("UserAndRole"); 69 entity.HasOne(u => u.Role).WithMany(r => r.Users); 70 }); 71 modelBuilder.Entity<UserAndRole>(entity =>
72 { 73 entity.ToTable("UserAndRole"); 74 entity.HasOne(u => u.User).WithMany(r => r.Roles); 75 }); 76 } 77 }
執行數據庫遷移命令Add-Migration init22222結果如下:
更新數據庫Update-Database,生成數據庫表結果如下:
至此、Code First主要步驟完成了,通過Code First正確創建了表之間一對多和多對多的關系,本實例中User和Role是多對多的關系,User和Orginazation是多對一的關系,
(二)Eager Loading(預加載)使用Include方法關聯預先加載的實體。在這里就不舉例說明了。
(三)Explicit Loading(直接加載)使用Entry方法,對於集合使用Collection,單個實體則使用Reference。在這里就不舉例說明了。
以上是我對Entity Framework Core的總結和使用,歡迎糾錯!!!