MVC3教程之實體模型和EF CodeFirst

  • 2019 年 10 月 7 日
  • 筆記

  在本節中,我們將使用Entity Framework 數據訪問技術來定義這些模型類,並對這些類來進行操作。EF支援一個被稱之為「code-first」的開發範例。Code-first允許你通過書寫一些簡單的類來創建模型對象,而不用關心這些類的持久化。你可以通過訪問這些類的方式來訪問資料庫,這是一種非常方便快捷的開發模式。

1.添加一個Model

  添加Model和添加普通類的操作是一樣的,默認的約定是將它放在Models文件夾中。我們在Models文件夾上面點擊右鍵,選擇「添加」>「類」,在打開的對話框中輸入類名「Book」,點擊「添加」按鈕。編輯器會為我們打開Book類,我們對這個類進行如下修改:

using System;  namespace MvcHelloworld.Models  {      publicclass Book      {          publicint BookID { get; set; }          publicstring BookName { get; set; }          publicstring Author { get; set; }          publicstring Publisher { get; set; }          publicdecimal Price { get; set; }          publicstring Remark { get; set; }      }  }

  我們將使用這個類來表示資料庫中的記錄。每一個Book類的實例對應資料庫中的一行,Book類中的每一個屬性被映射到資料庫中的一列。

2.添加資料庫上下文

  在Models文件夾下新建一個名為「BookDbContext」的類,編輯這個類,將該類派生自「DbContext」類,編輯後的程式碼如下:

using System;  using System.Data.Entity;  namespace MvcHelloworld.Models  {      publicclass BookDbContext : DbContext      {          public DbSet<Book> Books { get; set; }      }  }

  BookDbContext代表EF中Book在資料庫中的上下文對象,通過DbSet<Book>使實體類與資料庫關聯起來。Books屬性表示資料庫中的數據集實體,用來處理數據的存取與更新。BookDbContext派生自DbContext,需要添加System.Data.Entity的引用。

3.添加資料庫連接

  由於我們創建的是空的Mvc項目,所以在Web.config文件中,不包含任何的資料庫連接字元串,我們打開Web.config文件,為它添加一個資料庫連接字元串的配置:

<connectionStrings>      <add name="BookDbContext" connectionString=" Data Source=.SQLEXPRESS;Initial Catalog=db_book;Persist Security Info=True;Integrated Security=SSPI;"           providerName="System.Data.SqlClient"/>    </connectionStrings>

  我們將資料庫連接的name屬性設置為「BookDbContext」,這個連接會被BookDbContext類使用,並根據連接創建相應的資料庫。

4.為Book創建控制器和Index視圖

  按照第一節中的步驟,我們為Book模型創建一個控制器:在文件夾「Controllers」上面點擊右鍵 > 「添加」 > 「控制器」,在打開的添加控制器對話框中,將控制器的名稱修改為「BookController」,基架選擇中的模板選擇「空控制器」,如下圖:

  點擊「添加」按鈕後,VS會添加一個BookController的文件,該文件處於打開狀態。編輯Index方法的程式碼,查找作者為Tom的圖書:

public ActionResult Index()          {              var books = from b in db.Books                          where b.Author =="Tom"                          select b;              return View(books.ToList());          }

  在這段程式碼中,db是類BookDbContext的一個實例,我們在Controller類中定義如下:BookDbContext db = new BookDbContext();

  這是一個簡單的Linq查詢,在對資料庫進行操作時,EF會檢查當前的數據連接指定的資料庫是否被創建,如果沒有則有EF負責根據實體模型類創建資料庫、數據表;如果存在,EF會將查詢條件添加到Sql查詢語句,再將Sql語句發送到資料庫進行數據讀取。在完成數據讀取後,將數據轉換為實體對象集合。EF對資料庫的操作大致如此。

  在Index方法內點擊右鍵 > 「添加視圖」,在打開的「添加視圖」對話框,勾選「創建強類型視圖」,在模型類列表中選擇「Book(MvcHelloworld.Models)」,在支架模板列表中選擇「List」,如下圖:

  點擊「添加」按鈕,VS為我們在Views文件夾下創建了「Book」文件夾,並在Book文件夾中添加了文件「Index.cshtml」。

  Index.cshtml是我們的視圖頁面,我們可以把它看做一個模板,將我們的數據按照模板的格式進行輸出。在這個模板中,我們使用了Razor視圖引擎,在Razor中,我們可以使用@model 用來指定傳到視圖的 Model 類型,訪問傳入視圖的數據內容。我們簡單的修改程式碼,如果你了解HTML,這將是很簡單的事情:

@model IEnumerable<MvcHelloworld.Models.Book>  @{      ViewBag.Title = "圖書列表 - MvcBook";  }  <h2>圖書列表</h2>  <p>      @Html.ActionLink("增加圖書", "Create")  </p>  <table>      <tr>          <th>              圖書名稱          </th>          <th>              作者          </th>          <th>              出版社          </th>          <th>              價格          </th>          <th>              備註          </th>          <th></th>      </tr>  @foreach (var item in Model) {      <tr>          <td>              @Html.DisplayFor(modelItem => item.BookName)          </td>          <td>              @Html.DisplayFor(modelItem => item.Author)          </td>          <td>              @Html.DisplayFor(modelItem => item.Publisher)          </td>          <td>              @Html.DisplayFor(modelItem => item.Price)          </td>          <td>              @Html.DisplayFor(modelItem => item.Remark)          </td>          <td>              @Html.ActionLink("編輯", "Edit", new { id=item.BookID }) |              @Html.ActionLink("查看", "Details", new { id=item.BookID }) |              @Html.ActionLink("刪除", "Delete", new { id=item.BookID })          </td>      </tr>  }  </table>

  編譯並運行程式,在瀏覽器中輸入地址:http://localhost:xxx/Book,得到的運行結果如下:

  儘管沒有數據,但EF已經為我們創建了相應的資料庫。

  5.增加Create視圖

  「增加圖書」連接需要我們有一個Create控制器和與之對應的視圖。打開BookController文件,添加一個Create方法,程式碼如下:

public ActionResult Create()          {              return View();          }

  這個方法返回一個視圖,該視圖中包含了用戶要輸入的表單。現在我們來實現這個Create視圖,我們將在這個視圖中向用戶顯示追加數據時所需要用到的表單。在Create方法中點擊滑鼠右鍵,並點擊上下文菜單中的「添加視圖」。在「添加視圖」對話框中勾選「創建強類型視圖」,在模型類列表中選擇「Book(MvcHelloworld.Models)」,在支架模板列表中選擇「Create」,如下圖:

  點擊「添加」按鈕,VS會在Views/Book目錄下添加一個Create.cshtml文件,由於我們選擇了Create支架模板,所以在VS為我們生成了一些默認的程式碼。在這個視圖模板中,我們指定了強類型Book作為它的模型類,VS檢查Book類,並根據Book類的屬性,生成了對應的標籤名和編輯框,我們修改標籤名,使它顯示中文,修改後的程式碼如下:

@model MvcHelloworld.Models.Book  @{      ViewBag.Title = "新增圖書 - MvcBook";  }  <h2>新增圖書</h2>  <script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>  <script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>  @using (Html.BeginForm()) {      @Html.ValidationSummary(true)      <fieldset>          <legend>圖書</legend>          <div class="editor-label">              圖書名稱          </div>          <div class="editor-field">              @Html.EditorFor(model => model.BookName)              @Html.ValidationMessageFor(model => model.BookName)          </div>          <div class="editor-label">              作者          </div>          <div class="editor-field">              @Html.EditorFor(model => model.Author)              @Html.ValidationMessageFor(model => model.Author)          </div>          <div class="editor-label">              出版社          </div>          <div class="editor-field">              @Html.EditorFor(model => model.Publisher)              @Html.ValidationMessageFor(model => model.Publisher)          </div>          <div class="editor-label">              價格          </div>          <div class="editor-field">              @Html.EditorFor(model => model.Price)              @Html.ValidationMessageFor(model => model.Price)          </div>          <div class="editor-label">              備註          </div>          <div class="editor-field">              @Html.EditorFor(model => model.Remark)              @Html.ValidationMessageFor(model => model.Remark)          </div>          <p>              <input type="submit" value="增加"/>          </p>      </fieldset>  }  <div>      @Html.ActionLink("Back to List", "Index")  </div>

  分析這段程式碼:

  • @model MvcHelloworld.Models.Book:指定了該視圖模板中的「模型」強類型化成一個Book類。
  • @using (Html.BeginForm()){ }:創建一個Form表單,在表單中包含了對於Book類所生成的對應欄位。
  • @Html.EditorFor(model => model.BookName):根據模型生成模型中BookName的編輯控制項(生成一個Input元素)
  • @Html.ValidationMessageFor(model => model.BookName):根據模型生成模型中BookName的驗證資訊。

  編譯項目,在瀏覽器中輸入http://localhost:xxx/Book/Create, 查看新增介面,截圖如下:

6.添加Create的Postback方法

  在完成了添加Create視圖後,我們僅是可以將添加介面顯示出來,並不能實際的完成數據的添加,因為我們還沒有增加按鈕的處理方法,沒有實際的處理添加事件。為了能夠完成數據的增加,下面我們來添加一個Create的POSTBack方法,程式碼如下:

[HttpPost]          public ActionResult Create(Book book)          {              if (ModelState.IsValid)              {                  db.Books.Add(book);                  db.SaveChanges();                  return RedirectToAction("Index");              }              else                  return View(book);          }

  這時,我們在頁面上輸入數據,並點擊「增加」按鈕時,EF就會通過這段程式碼來添加一行資料庫記錄。打開資料庫,我們可以看到如下記錄:

  7.設置實體模型的數據驗證

  在ASP.NET MVC中,有一條作為核心的原則,就是DRY(「Don』t Repeat Yourself,中文意思為:不要讓開發者重複做同樣的事情,即「一處定義、處處可用」)原則。這樣可以減少開發者的程式碼編寫量,同時也更加便於程式碼的維護。

  ASP.NET MVC與EF code-first提供的默認驗證規則就是一個實現DRY原則的很好的例子。你也可以在模型類中顯式地追加一個驗證規則,然後在整個應用程式中都使用這個驗證規則。

  打開Book模型文件,添加 System.ComponentModel.DataAnnotations 的引用,並修改實體類的程式碼如下:

publicclass Book      {          publicint BookID { get; set; }          [Required(ErrorMessage="必須輸入圖書名稱")]          [StringLength(maximumLength:100, MinimumLength=1, ErrorMessage="最多允許輸入100個字元")]          publicstring BookName { get; set; }          [Required(ErrorMessage ="必須輸入作者名稱")]          publicstring Author { get; set; }          [Required(ErrorMessage ="必須輸入出版社")]          publicstring Publisher { get; set; }          publicdecimal Price { get; set; }          publicstring Remark { get; set; }      }

  將資料庫中之前生成的資料庫db_Book刪除掉,重新生成解決方案,打開新增頁面,不輸入任何數據的時候點擊「增加」按鈕,這個時侯,介面上會出現一些提示資訊,並且阻止了我們進行數據的提交操作。介面如下:

  這是一個簡單的驗證設置,通過設置驗證,EF還會在生成的資料庫中添加驗證資訊,例如是否為空、字元串長度等,如果要了解更多EF的功能,請看我的另一篇隨筆:Entity Framework 4.1 Code-First 學習筆記

  通過本節的學習,我們可以了解EF CodeFirst功能、MVC實體模型的操作等。對於實體的操作,還有更新、查看和刪除操作,筆者不再一一講解其步驟,只將控制器程式碼貼出,以供朋友們參照。視圖的程式碼可以參考自動生成,稍作修改即可。

BookController程式碼  using System;  using System.Collections.Generic;  using System.Linq;  using System.Web;  using System.Web.Mvc;  using MvcHelloworld.Models;  namespace MvcHelloworld.Controllers  {      publicclass BookController : Controller      {          BookDbContext db =new BookDbContext();          public ActionResult Index()          {              var books = from b in db.Books                          select b;              return View(books.ToList());          }          public ActionResult Create()          {              return View();          }          [HttpPost]          public ActionResult Create(Book book)          {              if (ModelState.IsValid)              {                  db.Books.Add(book);                  db.SaveChanges();                  return RedirectToAction("Index");              }              else                  return View(book);          }          public ActionResult Edit(int id)          {              Book book = db.Books.Find(id);              if (book ==null)                  return RedirectToAction("Index");              return View(book);          }          [HttpPost]          public ActionResult Edit(Book newBook)          {              try              {                  Book oldBook = db.Books.Find(newBook.BookID);                  UpdateModel(oldBook);                  db.SaveChanges();                  return RedirectToAction("Details", new { id = newBook.BookID });              }              catch (Exception ex)              {                  ModelState.AddModelError("", "修改失敗,請查看詳細錯誤資訊:"+ ex.Message);              }              return View(newBook);          }          public ActionResult Details(int id)          {              Book book = db.Books.Find(id);              if (book ==null)                  return RedirectToAction("Index");              return View(book);          }          public ActionResult Delete(int id)          {              Book book = db.Books.Find(id);              if (book ==null)                  return RedirectToAction("Index");              return View(book);          }          [HttpPost]          public ActionResult Delete(int id, FormCollection collection)          {              Book book = db.Books.Find(id);              db.Books.Remove(book);              db.SaveChanges();              return RedirectToAction("Index");          }      }  }