七色花基本權限系統(4) - 初步使用EntityFramework實現用戶登錄


這篇日志將演示:

1、利用EF的Code First模式,自動創建數據庫

2、實現簡單的用戶登錄(不考慮安全僅僅是密碼驗證)

 

為什么選擇EntityFramework

第一,開發常規中小型系統,能夠提高開發效率。

針對小型系統,ORM提高開發效率那是立竿見影。而且linq+lambda的用戶體驗非常棒,讓代碼可讀性大大增強。即使把linq寫得很爛,小系統也無所謂。

針對中型系統,在對ORM有一定了解並且對linq to entity也掌握一定技巧的基礎上,使用ORM還是可以提高開發效率。

第二,對開發人員的sql技巧沒有要求。

針對不同的數據庫,需要寫的sql語句是有差別的。寫linq不用管這個,不會寫sql都沒事。

我不喜歡寫sql,寫得也很爛。不過EF也支持開發人員自己寫sql。

 

為什么選擇EF的Code First

第一,在開發階段時,可以做到真正的忽略數據庫(沒錯我就是那么討厭數據庫硬編程的方式)。

第二,實體類屬性數據類型的控制,可以很精確 (比如你可以定義實體類的某個屬性的數據類型為枚舉)

第三,項目穩定后,即使想“不通過實體類去更新數據庫表”,也可以。關閉EF對數據庫的檢測,數據庫中手動修改結構,同時手動調整實體類。

第四,EF7中,將只會保留Code First模式,說明官方也認為Code First才是ORM的正確使用方式

 

數據實體

首先要注意分離數據實體層和數據上下文層。

新建類庫項目,名稱S.Framework.Entity,用來存放映射到數據庫的實體類。

同時為考慮“多個數據庫”的可能,以文件夾進行隔離,在根目錄下創建文件夾Master(一個區別標識,可以按需定義)。這個設計將大大影響后面的架構設計,請務必注意理解。

根據需求抽象出實體模型。

演示簡單的用戶登錄功能,一個用戶表即可。

  1 namespace S.Framework.Entity.Master
  2 {
  3     /// <summary>
  4     /// 用戶
  5     /// </summary>
  6     public class SysUser
  7     {
  8         /// <summary>
  9         /// 主鍵
 10         /// </summary>
 11         public string ID { get; set; }
 12 
 13         /// <summary>
 14         /// 用戶名
 15         /// </summary>
 16         public string UserName { get; set; }
 17 
 18         /// <summary>
 19         /// 登錄密碼
 20         /// </summary>
 21         public string Password { get; set; }
 22 
 23         /// <summary>
 24         /// 是否禁用
 25         /// </summary>
 26         public bool IsDisabled { get; set; }
 27 
 28         /// <summary>
 29         /// 是否刪除
 30         /// </summary>
 31         public bool IsDeleted { get; set; }
 32 
 33         /// <summary>
 34         /// 獲取或設置一個 <see cref="string"/> 值,該值表示實體對象的數據創建者。
 35         /// </summary>
 36         public virtual string CreateUser { get; set; }
 37 
 38         /// <summary>
 39         /// 獲取或設置一個 <see cref="DateTime"/> 值,該值表示實體對象的數據創建時間。
 40         /// </summary>
 41         public virtual DateTime CreateDate { get; set; }
 42 
 43         /// <summary>
 44         /// 獲取或設置一個 <see cref="string"/> 值,該值表示實體對象的數據最后修改者。
 45         /// </summary>
 46         public virtual string LastModifyUser { get; set; }
 47 
 48         /// <summary>
 49         /// 獲取或設置一個 <see cref="DateTime"/> 值,該值表示實體對象的數據最后修改時間。
 50         /// </summary>
 51         public virtual DateTime? LastModifyDate { get; set; }
 52     }
 53 }
SysUser.cs

請一定注意實體類的命名空間。

為區分各實體類的功能,可以套一個文件夾進行分類,比如System、Basic、Hr等。如下圖:

image

請一定注意實體類的命名空間,命名空間的最后一級必須是“數據庫標識”。

這里多講一句,不要在實體類中增加“數據庫映射”相關的特性。因為數據實體和數據核心應該是解耦的,作為數據實體,它不關心使用自己的數據驅動是EF還是dapper,那么就不該在它的身上體現任何“站隊伍”的痕跡。

 

數據核心

數據核心應該能夠支持多種數據驅動。這里先演示EF的使用。

新建類庫項目,名稱S.Framework.DataCore,然后從nuget上先安裝EntityFramework。

創建結構如下圖:

image

EntityContexts用來存儲EF的數據庫上下文,因為在實體層定義了Master作為數據庫標識,因此在這里建立相對應的數據庫上下文。

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Linq;
  4 using System.Text;
  5 using System.Threading.Tasks;
  6 using System.Data.Entity;
  7 using System.Data.Entity.ModelConfiguration.Conventions;
  8 
  9 namespace S.Framework.DataCore.EntityFramework.EntityContexts
 10 {
 11     /// <summary>
 12     /// 數據庫上下文
 13     /// </summary>
 14     public class MasterEntityContext : DbContext
 15     {
 16         /// <summary>
 17         /// 構造函數
 18         /// </summary>
 19         /// <param name="nameOrConnectionString">數據庫名稱或連接字符串。</param>
 20         public MasterEntityContext(string nameOrConnectionString)
 21             : base(nameOrConnectionString)
 22         { }
 23 
 24         /// <summary>
 25         /// 模型配置重寫
 26         /// </summary>
 27         /// <param name="modelBuilder">數據實體生成器</param>
 28         protected override void OnModelCreating(System.Data.Entity.DbModelBuilder modelBuilder)
 29         {
 30             // 禁用一對多級聯刪除
 31             modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
 32             // 禁用多對多級聯刪除
 33             modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>();
 34             // 禁用表名自動復數規則
 35             modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
 36         }
 37     }
 38 }
 39 
MasterEntityContext.cs

數據庫上下文創建之后,還需要關聯數據實體類,這樣EF才能知道“數據庫表應該是哪些實體”。在S.Framework.DataCore中引用S.Framework.Entity,然后在MasterEntityContext的中增加屬性,用來表示對實體的使用。

  1 /// <summary>
  2 /// 用戶
  3 /// </summary>
  4 public DbSet<SysUser> Users { get; set; }
映射關聯

 

通過EF自動創建數據庫

到這步,數據實體、數據上下文都有了,理論上來說,就可以在WebUI層中使用了。為演示EF效果,就先這么使用吧,后面再慢慢地完善。

首先,UI層需引用Entity和DataCore。然后在UI層的web.config文件中配置數據庫信息。

注意一下,EF-CodeFirst模式能夠自動創建數據庫,所以在配置數據庫連接字符串的時候,設置一個不存在的數據庫名是完全沒問題的。

  1 <connectionStrings>
  2     <add name="matrixkey" connectionString="server=MATRIXKEY\MATRIXKEYSQL2012;database=S-SevenMaster-1;uid=sa;password=1;" providerName="System.Data.SqlClient" />
  3 </connectionStrings>
映射關聯

還需要在UI層也引用EntityFramework(這個耦合會在后面移除掉,此處為做演示先引用),然后修改HomeController來嘗試操作數據庫。

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Linq;
  4 using System.Web;
  5 using System.Web.Mvc;
  6 
  7 using S.Framework.Entity.Master;
  8 using S.Framework.DataCore.EntityFramework.EntityContexts;
  9 
 10 namespace S.Framework.WebClient.Controllers
 11 {
 12     public class HomeController : Controller
 13     {
 14         public ActionResult Index()
 15         {
 16             var db = new MasterEntityContext("matrixkey");
 17 
 18             //初始化用戶實體類,只需要定義不該為空屬性即可
 19             //其實String類型的屬性,通過EF映射到數據庫中后,字段都是允許為空的,這個需要通過“實體配置類”來進行控制,下一章節會講。
 20             var entity = new SysUser { ID = Guid.NewGuid().ToString(), UserName = "admin", Password = "123456", CreateDate = DateTime.Now, CreateUser = "admin" };
 21             //將用戶對象附加給數據庫上下文(這僅僅是內存級別的操作)
 22             db.Users.Add(entity);
 23             //數據庫上下文保存更改(提交變更到數據庫執行)
 24             db.SaveChanges();
 25 
 26             return View();
 27         }
 28     }
 29 }
通過EF操作數據庫

編譯生成,運行。如果成功打開/Home/Index頁面,則表示執行成功。可以打開數據庫,檢查是否創建了名為“S-SevenMaster-1”的數據庫,同時檢查該數據庫下是否創建了SysUser表,並且里面有一條admin數據。

image

image

__MigrationHistory表是EF自動生成的用來記錄“數據庫結構變更操作”的歷史表,不用管它。有興趣的讀者可以研究一下,也很有意思。

 

用戶登錄

先注釋HomeController中那段往數據庫里添加admin用戶的代碼,不然每次打開/Home/Index頁面都會新增admin用戶信息。

先有模型后有天,要登錄先定義登錄頁面的表單數據模型吧。可以在Models文件夾建立LoginModel類。

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Linq;
  4 using System.Web;
  5 
  6 namespace S.Framework.WebClient.Models
  7 {
  8     /// <summary>
  9     /// 登錄數據模型
 10     /// </summary>
 11     public class LoginModel
 12     {
 13         /// <summary>
 14         /// 登錄用戶名
 15         /// </summary>
 16         public string UserName { get; set; }
 17 
 18         /// <summary>
 19         /// 登錄密碼
 20         /// </summary>
 21         public string Password { get; set; }
 22 
 23         /// <summary>
 24         /// 提示信息
 25         /// </summary>
 26         public string Message { get; set; }
 27     }
 28 }
登錄數據模型類

然后創建AccountController,並定義登錄頁面的Action如下:

  1 public ViewResult Login()
  2 {
  3       var model = new S.Framework.WebClient.Models.LoginModel();
  4 
  5       return View(model);
  6 }
登錄頁面Action

右鍵Login這個Action創建視圖,選擇不需要布局頁。登錄界面不是重點,此處就不貼頁面代碼一筆帶過了。

在控制器中還需定義“登錄操作”的Action,邏輯暫時比較簡單,直接上代碼:

  1 [ValidateAntiForgeryToken]
  2 [HttpPost]
  3 public ActionResult Login(S.Framework.WebClient.Models.LoginModel model)
  4 {
  5     var db = new MasterEntityContext("matrixkey");
  6     var entity = db.Users.Where(w => w.UserName == model.UserName).FirstOrDefault();
  7     if (entity == null)
  8     {
  9         model.Message = "用戶名不存在";
 10     }
 11     else
 12     {
 13         if (entity.Password != model.Password)
 14         {
 15             model.Message = "密碼輸入不正確";
 16         }
 17         else
 18         {
 19             return RedirectToAction("Index", "Home", new { });
 20         }
 21     }
 22 
 23     return View(model);
 24 }
登錄操作Action

這里注意2個特性的作用。ValidateAntiForgeryToken是用來阻止偽造的登錄請求的,需要視圖中有相應信息配合使用。HttpPost是用於區別“登錄頁面的Login和登錄操作的Login”,需要視圖中表單的提交方式也是Post。順帶一句,控制器中的Action是不能重載的,但可以利用表示HTTP方法的特性加以區分。

身份驗證的功能,下面單獨拎出來講,先跑通密碼驗證的邏輯。

數據模型、登錄頁面、登錄操作,都已經完成,運行一下效果,用戶admin,密碼123456,成功跳轉到首頁。

 

說明一下,安全身份驗證的功能將放在后面再講。

因為要演示封裝架構的過程,而現在連數據倉儲層和業務層都沒有創建,不方便單獨寫身份驗證部分的代碼。

 

下一章節,將演示EF實體配置的使用和利用T4模板自動生成實體配置。

 

截止本章節,項目源碼下載:點擊下載(存在百度雲盤中)


免責聲明!

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



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