MVC5+EF6 入門完整教程九

前一陣子臨時有事,這篇文章發佈間隔比較長,咱們先回顧下以前的內容,每篇文章用一句話總結重點。 html

文章一 MVC核心概念簡介,一個基本MVC項目結構 數據庫

文章二 經過開發一個最基本的登陸界面,介紹瞭如何從Controller中獲取表單數據 服務器

文章三 EF的整個開發過程 app

文章四 EF基本的CRUD和經常使用的HtmlHelper 函數

文章五 使用佈局頁(模板頁)改造UI 佈局

文章六 分部視圖(Partial View) 學習

文章七 排序過濾分頁 測試

文章八 不丟失數據進行數據庫結構升級 ui

以上若是有不清楚的能夠再回去看一下。 this

 

文章提綱

  • 理論基礎
  • 應用場景
  • 總結

理論基礎

基於前面的文章,本次咱們更近一步,進行更加深刻的講解, 首先介紹下Attribute配置Data Model.

使用Attribute配置Data Model, 能夠指定formatting, validation, database mapping rules

約定:下圖中三種狀況通常資料都翻譯成"屬性",爲了區分,咱們用下圖中的表述方式。

接下來,咱們先對經常使用的attribute進行舉例說明。

1、經常使用Attribute

DataType,DisplayFormate

首先打開ModelsàSysUser.cs

添加 public DateTime CreateDate { get; set; }

增長完以後及時使用Code First Migrations 方式更新數據庫。(否則運行時會報contex和database不一致的錯誤)

Note

注意把Migrations\ Configuration.cs中Seed方法中內容註釋掉,由於

模型變了,插入示例數據時會報一個錯誤。

運行 add-migration AddCreateDateToSysUserupdate-database便可更新

更新後隨便在數據庫中插入兩個日期值。

Code First Migrations 方式更新數據庫詳細作法參加上篇文章。

 

接着修改Views\Account\Index.cshtml,把建立日期顯示出來,以下方框處。

你們注意到,默認狀況下會顯示出時間,咱們只須要顯示到日就能夠了。

下面咱們就把CreateDate調整到咱們須要的格式。

打開 Models\SysUser.cs, 作以下修改。

DataType 屬性用來指定更加具體的數據類型,DataType枚舉值提供了一些常見的類型,好比Date,Time,EmailAddress等。

可是DataType不能指定數據類型的顯示格式,例如日期要什麼格式顯示。

默認狀況下顯示格式會根據電腦的設定顯示。

這個時候就須要配合使用DisplayFormate屬性來指定格式。

[DisplayFormat(DataFormatString="{0:yyyy-MM-dd}",ApplyFormatInEditMode=true)]

 

StringLength

你能夠指定數據驗證規則以及出錯信息。

StringLength屬性設置了數據庫中存儲字段的最大長度,爲程序提供客戶端和服務器端的驗證。一樣用這個屬性也能夠指定最小長度,不過不影響數據庫的結構。

一樣更新下數據庫

add-migration MaxLengthOnNames
update-database

先去數據庫看下,能夠看到已經有長度限制了。

咱們再修改下Create方法,測試下驗證。

以前咱們的模型太簡陋了,爲了看到效果,再作兩處修改。

Views\Account\Create.cshtml增長一個Helper:ValidationMessageFor用來顯示驗證信息

Controllers\AccountController.cs增長一個判斷條件ModelState.IsValid,否則會出錯。

運行能夠看到以下效果:

 

Column

這個屬性也很是實用。

有時會有這麼一種狀況,咱們Model中的字段和數據庫中表的字段要用不一樣的命名。例如咱們Model中命名爲UserName,數據庫表中命名爲LoginName.

這個時候就用到Column了。

一樣運行更新指令。

add-migration ColumnLoginName

update-database

打開數據庫能夠看到UserName已經變成LoginName了。


下面再列出其餘經常使用的attribute, 就不舉展開講了,很容易能夠看懂,你們能夠本身嘗試。

[Display(Name="用戶名")]

[StringLength(10,MinimumLength=1,ErrorMessage="名字在1和10個字之間")]

 

Note

1.能夠將多個屬性寫在一塊用逗號隔開,例如

[Column("FirstName"),Display(Name = "First Name"),StringLength(50, MinimumLength=1)]

2.對某一些類型來講不須要使用Required, 例如DateTime, int,double,float,由於這些值類型不能被賦予空值,所以他們天生就具備Required的特性。

 [Column(TypeName="money")] 

public decimal Budget { get; set; } 

以前用Column能夠改變數據庫中列名。

指定Column的TypeName能夠改變SQL data type,這個例子中就是知道使用SQL Server的money類型。

Column mapping通常來講不須要,由於EF一般會基於你爲property定義的CLR類型選擇合適的SQL Server data type.

The CLR decimal type maps to a SQL Server decimal type.

詳細對應表:https://msdn.microsoft.com/en-us/library/bb896344.aspx

 

2、Lazy, Eager, and Explicit Loading of Related Data

前面文章中咱們介紹過顯示關聯表數據的方法。

第四篇文章介紹過經過navigation 屬性顯示關聯表數據。

本篇文章就係統的講解下多表關聯數據顯示的問題。

有三種方式EF能夠加載關聯數據到一個實體的navigation屬性中,下面我就直接用MSDN上的截圖來講明。

Lazy loading

第一次讀取entity的時候不會加載。

當須要讀取navigation property的時候,相關的數據將會被自動讀取。

這種狀況會致使屢次查詢數據庫。

Eager loading

當讀取entity的時候,相關數據會被一塊兒讀取。

通常來講這種方式會產生一個join query來獲取全部須要的數據。

經過Include方法來指定eager loading.

Explicit loading    

和lazy loading相似,除了須要在代碼中明確指定須要獲取的關聯數據。

在讀取navigation property時explicit loading 不會自動發生,你須要手動加載相關數據。

經過獲取object state manager entry for entity,調用Collection.Load method for collections或者Reference.Load method for properties that hold a single entity.

通常來講,只有在關閉lazying loading的時候纔會使用explicit loading

lazy loading 和 explicit loading都不當即獲取property values,它們也被稱做deferred loading.

Disable lazy loading before serialization

disable lazy loading的兩種方式:

1.對特定的navigation properties來講,省略property的virtual關鍵字就能夠了

2.對全部navigation properties來講, 在context類中,構造函數中設置LazyingLoadingEnabled 爲false便可。

this.Configuration.LazyLoadingEnabled = false;

 

 

 

 

應用場景

場景一:多對一關係,顯示用戶及相應的部門(* to 0 or 1)

新建一個entity: SysDepartment

咱們約定,某個用戶只能歸屬於0個或1個部門。

即用戶和部門的關係爲(* to 0 or 1)

原來的SysUser中添加一個以下兩個property

使用 code first migrations的方式更新下數據庫。能夠看到新的表結構已經生成了。

去數據庫中SysDepartment添加兩筆資料。

去數據庫中SysUser修改用戶對應的department

先看下原來的Views\Account\Index.cshtml

咱們原來是顯示SysUser主表內容,當點擊Details時經過navigation property實現SysUseràSysUserRoleàSysRole多表間查詢。

如今咱們增長一列Department, 讓這個表格能直接顯示SysUser主表及相應的Department內容。

咱們使用Eager Loading的方式將Department的內容也加載進去,打開Controllers\AccountController.cs, 在index修改一處地方:

修改對應的View

運行,能夠看到Department中的內容已經被咱們加載進來了。

這個就是第一種場景,多對一的狀況。

下面咱們再來看多對多的狀況。

場景二:多對多關係

多對多關係能夠拆解成一對多的關係,例如用戶和角色(* to *)可拆解成:

顯示用戶及相應的角色(1 to *)

顯示角色及相應的用戶(1 to *)

爲了演示這個場景,咱們新建一個ViewModel,將須要顯示的表都放進去。

建立相應的Controller和View

由於前面的文章已經將基本的用法都講過了,我這裏就直接貼出代碼以及最終的展現結果,若是有不理解的部分再給我留言。

Controllers\UserRoleController.cs:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Web;

using System.Web.Mvc;

using MVCDemo.ViewModels;

using MVCDemo.DAL;

using MVCDemo.Models;

using System.Data.Entity;

 

 

namespace MVCDemo.Controllers

{

public class UserRoleController : Controller

{

private AccountContext db = new AccountContext();

//

// GET: /UserRole/

public ActionResult Index(int? id)

{

var viewModel = new UserRoleIndexData();

viewModel.SysUsers = db.SysUsers

.Include(u=>u.SysDepartment)

.Include(u => u.SysUserRoles.Select(ur => ur.SysRole))

.OrderBy(u => u.UserName);

 

if (id!=null)

{

ViewBag.UserID = id.Value;

viewModel.SysUserRoles = viewModel.SysUsers.Where(u => u.ID == id.Value).Single().SysUserRoles;

viewModel.SysRoles = (viewModel.SysUserRoles.Where(

ur => ur.SysUserID == id.Value)).Select(ur=>ur.SysRole);

 

}

return View(viewModel);

}

    }

}

 

Views\UserRole\Index.cshtml

@model MVCDemo.ViewModels.UserRoleIndexData

 

@{

ViewBag.Title = "Index";

Layout = "~/Views/Shared/_LayoutAdmin.cshtml";

}

 

<h2>UserRoles</h2>

 

<p>

@Html.ActionLink("Create New", "Create")

</p>

 

<table class="table table-striped">

<tr>

<th>

UserName

</th>

<th>

Email

</th>

<th>

CreateDate

</th>

<th>

Department

</th>

<th>

Roles

</th>

<th></th>

</tr>

@foreach (var item in Model.SysUsers)

{

string selectedRow = "";

if (item.ID==ViewBag.UserID)

{

selectedRow = "success";

}

<tr class="@selectedRow">

<td>

@Html.DisplayFor(modelItem => item.UserName)

</td>

<td>

@Html.DisplayFor(modelItem => item.Email)

</td>

<td>

@Html.DisplayFor(modelItem => item.CreateDate)

</td>

<td>

@if (item.SysDepartment != null)

{

@item.SysDepartment.DepartmentName

}

</td>

<td>

@{

foreach (var userRole in item.SysUserRoles)

{

@userRole.SysRole.RoleName <br />

}

}

</td>

<td>

@Html.ActionLink("Select", "Index", new { id = item.ID })

 

</td>

</tr>

}

</table>

 

@if (Model.SysRoles != null)

{

<h3>Related Roles</h3>

<table class="table table-striped">

<tr>

<th>RoleName</th>

<th>RoleDesc</th>

</tr>

 

@foreach (var item in Model.SysRoles)

{

<tr>

<td>

@item.RoleName

</td>

<td>

@item.RoleDesc

</td>

</tr>

}

</table>

}

 

 

最終展現結果:

總結

1、掌握經常使用attribute

DataType

例子:[DataType(DataType.Date)]

DisplayFormat

例子:

[DisplayFormat(DataFormatString="{0:yyyy-MM-dd}",ApplyFormatInEditMode=true)]

[DisplayFormat(NullDisplayText = "No grade")]

StringLength

例子:

[StringLength(10,MinimumLength=1,ErrorMessage="名字在1和10個字之間")]

Column

例子:

[Column("FirstName")]

[Column(TypeName="money")]

Display

例子:

[Display(Name="用戶名")]

 

2、掌握加載多表數據兩種應用場景

 

好了,到目前爲止,使用MVC+EF開發的基本知識差很少都齊全了。

在下一課,也就是咱們第一階段的最後一課:MVC5+EF6入門完整教程十,咱們將再講解下數據更新的部分,以及如何使用原生SQL,如何調用存儲過程等。

祝你們新年快樂,學習進步!

相關文章
相關標籤/搜索