MVC5+EF6 入門完整教程3 :EF完整開發流程


 

概述 & 要點

下面是本文要點,正文部分會有詳細介紹。

  • EF架構圖
  • 新建基於EF的Data Model的約定
  • 關於ORM的重要概念,和傳統方式開發的區別
  • EF開發的整體過程

 

一、根目錄下新建一個 ViewModels文件夾

Models文件夾存放對應於數據庫表的實體;

View顯示的數據和Models中實體模型不一定能對應上, 因此需要建立一個文件夾ViewModels專門存放View使用的自定義數據模型;

 

二、根目錄下新建一個DAL 文件夾

           DAL 存放數據訪問相關類。

            NOTE 本文中放AccountContext.cs, AccountInitializer.cs

 

三、創建相關類(Data Model)

針對用戶建立三個相關的類:

SysUser, SysRole, SysUserRole

這是用戶權限管理RBAC (Role – Based Access Control)的一個典型模型, 更復雜的模型都可以在這個基礎上進行擴展。

OK,下面我們就開始新建這個模型。

我們先去網上找個大致的關系圖做參考,打開百度,輸入 user role , 搜索圖片。

挑一個類似的做參考。

 

NOTE 權限相關是系統管理范疇的,不涉及具體業務,我起名字的時候都加了Sys前綴,這樣和業務區隔開來。

參考上面這個圖建立 Data Model

SysUser Entity

SysRole Entity

SysUserRole Entity

對於上面幾個類的約定和說明:

  1. EF生成數據庫的 主鍵:約定: EF默認會將IDclassnameID生成為主鍵 MSDN建議保持風格的一致性, 都用ID或classnameID, 我們這里都用ID)
  2. EF生成數據庫的外鍵 :  約定:<navigation property name><primary key property name>這種形式的會成為外鍵

    例如外鍵 SysUserID = SysUser(navigation property) + ID(SysUser的主鍵)

  3. 定義為virtual的幾個屬性是 navigation 屬性(virtual非必須, 只是慣例用法, 后面文章將會講解用virtual的好處).

    navigation 屬性保存着其他的關聯entity(entities)

    示例中, SysUser和SysUserRole是一對多的關系, SysRole和SysUserRole也是一對多的關系.

    如果是 "多", 屬性類型就必須是list( 這里用的是Icollection )

四、創建 Database Context

前置條件:安裝EF

在程序包管理器控制台輸入 install-package entityframework

 

去MSDN上查看下EF的架構圖:http://msdn.microsoft.com/en-us/data/aa937709

從上圖可以看出,EF框架在底層是通過調用ADO.NET來實現數據庫操作的。

多轉一道彎,性能和靈活性肯定會受到影響,所以本系列文章結束后同樣也會給出MVC+ADO.NET的方案,大家可以根據需要選擇。

NOTE

微軟官方推出的ORM框架主要有Linq to SQLEntity Framework.

EF是目前最新的,也是推薦配合MVC使用的框架。

實際操作前再補充一些重要概念:

如果不用ORM框架,我們一般這樣來使用ADO.NET進行數據庫開發:

  1. 將ADO.NET對數據庫的操作封裝到一個類里SqlHelper中
  2. 在DAL層調用SqlHelper
  3. 其他層再調用DAL進行數據庫操作

使用ORM之后,以前面的SysUser為例:

O(Object) ---> 程序中的類 SysUser, 就是對象

R (Relation) ---> 數據庫中的表

M(Mapping) ---> O和R的映射關系

ORM對傳統方式的改進:

充當橋梁,實現了關系數據和對象數據的映射,通過映射自動產生SQL語句

對常用的操作,節省了寫SQL語句的步驟。

 

創建類 AccountContext.cs , 繼承System.Data.Entity.DbContext, 這個類完成EF的功能。

主要做下面三件事:

  1. 為每個 entity set創建一個DbSet

    在EF中,通常情況下一個entity set對應數據庫中的一張表,一個entity對應表中的一行。

  2. 指定一個連接字符串

    構造函數中的 base("AccountContext") 。

    默認情況下和類名一樣,即AccountContext,我們顯式的給他指定出來。

  3. 指定單數形式的表名

    >();

    默認情況下會生成復數形式的表,如SysUsers

    NOTE 表名用單復數形式看各自的習慣,沒有明確的規定。有的公司表名全用單數,有的公司根據表的意思,有單數也有復數。

    public class AccountContext:DbContext
    {
        public AccountContext():base("AccountContext")
        {
        }
        public DbSet<SysUser> SysUsers { get; set; }
        public DbSet<SysRole> SysRoles { get; set; }
        public DbSet<SysUserRole> SysUserRoles { get; set; }
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
        }
    }

 

五、在web.config配置連接字符串

如下圖,貼着appSettings配置節上面添加。注意要web.config中要加上紅字部分,不然會出錯。

  <connectionStrings>
    <add name="AccountContext" connectionString="Data Source=.;database=MvcDemo;uid=sa;pwd=6617saSA;
AttachDBFilename=|DataDirectory|\MvcDemo.mdf;
" providerName="System.Data.SqlClient"/> </connectionStrings>

 或先建立數據庫MVC_Demo

  <connectionStrings>
    <add name="DbConStr" connectionString="Data Source= WFYWORK\SQLEXPRESS ;Initial Catalog=MVC_Demo;Persist Security Info=True;User ID=sa;Password=6617saSA"
              providerName="System.Data.SqlClient" />
  </connectionStrings>

 

NOTE AttachDBFilename=|DataDirectory|\MVCDemo.mdf設定了數據庫文件的存放位置:在項目根目錄的App_Data文件夾下

 

六、創建AccountInitializer, 使用EF初始化數據庫,插入示例數據

Entity Framework 數據庫初始化的三種方法

1、CreateDatabaseIfNotExists:在沒有數據庫時創建一個,這是默認行為。

2、DropCreateDatabaseIfModelChanges:模型改變時,自動重新創建一個新的數據庫,就可以用這個方法。這在開發過程中非常有用。

3、DropCreateDatabaseAlways:每次運行時都重新生成數據庫。

目前在開發階段,不用管數據丟失的問題,直接drop and re-create比較方便。

等系列文章結束后會講解生產環境中如何不丟失數據修改schema

6.1、新建一個類繼承

public class  AccountInitializer: DropCreateDatabaseIfModelChanges<AccountContext>

{

}

 

6.2、重寫Seed方法,插入數據

    public class AccountInitializer : DropCreateDatabaseIfModelChanges<AccountContext>
    {
        protected override void Seed(AccountContext context)
        {
            var sysUsers = new List<SysUser>
            {
                new SysUser { UserName="吳先生",Password="123456" },
                new SysUser { UserName="徐先生",Password="123456" }
            };

            sysUsers.ForEach(s => context.SysUsers.Add(s));
            context.SaveChanges();

            var sysRoles = new List<SysRole>
            {
                new Models.SysRole {RoleName="Administrators",RoleDesc="Administrators具有系統管理的所有權限" },
                new Models.SysRole {RoleName="General Users",RoleDesc="General Users 可以訪問已經授權的數據" }
            };

            sysRoles.ForEach(s => context.SysRoles.Add(s));
            context.SaveChanges();

            base.Seed(context);
        }
    }

 

6.3、運行

在Global.asax里執行

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();

    WebApiConfig.Register(GlobalConfiguration.Configuration);
    FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
    RouteConfig.RegisterRoutes(RouteTable.Routes);

    Database.SetInitializer<AccountContext>(new AccountInitializer ()); 
}

或在EF上下文的OnModelCreating里執行

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
  
Database.SetInitializer<AccountContext>(new AccountInitializer ());
base.OnModelCreating(modelBuilder);
}

===================================  下面的方法沒有測試  =================================== 

修改web.config, 通知EF使用我們剛剛寫好的AccountInitializer類。

找到entityFramework配置節,添加下圖方框處內容。

context 配置節中, type 的值對應 (AccountContext的完整描述,程序集

databaseInitializer 配置節中 , type 的值對應 (initializer class 的完整描述,程序集

NOTE : 如果你不想EF使用某個context, 可以將下面方框處設置為true.

 

====================================================================== 

七、完成數據庫查詢驗證

Database.SetInitializer(new AccountInitializer ()); 僅僅是設置數據庫初始化器,不建立數據庫。

 

 ***********************************************************************************************************************

現在EF一切就緒.

運行程序,當第一次連接數據庫時,EF比較model(AccountContext和entity classes) 和database. 如果兩邊不一致,程序將會drop and re-create數據庫。

因為目前我們還沒有連接數據庫的操作,所以EF還沒發揮作用。

現在我們完成前面的Login功能。

添加Email字段:

在public class User里面添加個Email字段。

在AccountInitializer.cs--->Seed函數里增加這個字段

namespace MVCDemo.Models
{
    public class User
    {
        public int ID { get; set; }
        public string UserName { get; set; }
        public string Email { get; set; }
        public string Password { get; set; }
        public virtual ICollection<UserRole> UserRoles { get; set; }
    }
}
var Users = new List<User>
            {
                new User { UserName="張三", Email="張三@139.com",Password="123456" },
                new User { UserName="李四",Email="李四@139.com",Password="123456" }
            };

 

NOTE 添加一個Email是因為之前的登錄頁面填入的是Email值,后面將會輸入Email和Password到數據庫中進行比對。

在AccountController.cs實例化一個database context 對象:DemoContext db = new DemoContext();

        [HttpPost]
        public ActionResult Login(FormCollection fc)
        {
            string email = fc["inputEmail3"];
            string password= fc["inputPassword3"];
            var user = db.Users.Where(a => a.Email == email && a.Password == password);
            if(user.Count()>0)
            {
                ViewBag.LoginState = email + "登錄后...";
            }
            else
            {
                ViewBag.LoginState = email + "用戶不存在...";
            }     
            return View();
        }

 

 

運行Login.cshtml頁面,輸入正確的和錯誤的登錄信息驗證下。

另外再檢查一下數據庫部分是否符合我們的預期:

  1. 打開數據庫,發現MVCDemo這個數據庫已經新建,示例數據已經插入。
  2. 打開項目的App_Data 文件夾,發現數據庫文件已經存在。【 在沒有按照數據庫,使用VS自帶的數據庫的情況下

     

總結

OK,到此為止,我們搭建好了EF框架,進行了數據庫的初始化,查詢了一條用戶信息。

需要說明的是,現在的登錄功能還比較簡陋,不是真正的登錄功能(例如輸入項還缺少驗證,密碼還沒有加鹽),只是為了說明EF的用法。根據系列文章講述知識點的需要,最終會實現完整功能。

最后再回顧下本篇文章的重點:掌握使用EF開發的整個過程

創建Data Model---> 創建Database Context ---> 創建databaseInitializer ---> 配置entityFramework的context配置節

希望大家能清晰的了解上面整個過程,理解每一個過程的作用。

 


免責聲明!

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



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