1.本章學習內容
1.實現用戶信息的批量刪除
2.實現用戶數據的初始化以及當實體發生改變時自動更改數據庫
1.實現用戶信息的批量刪除
在前面幾章里我們已經完成了用戶信息的添加,修改,列表展示,現在我們來完成刪除功能。
首先,修改UserInfo控制器添加用書刪除的處理Action,完整代碼如下:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using MyShopTest.Models; using System.Data; namespace MyShopTest.Controllers { public class UserInfoController : Controller { //數據訪問 private MyShopDataEntities db = new MyShopDataEntities(); /// <summary> /// 用戶列表Action /// </summary> /// <returns></returns> public ActionResult Index() { var users = db.UserInfos.ToList(); return View(users); } /// <summary> /// 添加用戶頁面展示 /// </summary> /// <returns></returns> public ActionResult Create() { return View(); } /// <summary> /// 添加用戶處理 /// </summary> /// <returns></returns> [HttpPost] public ActionResult Create(UserInfo user) { db.UserInfos.Add(user); db.SaveChanges(); return RedirectToAction("Index"); } /// <summary> /// 編輯用戶頁面展示 /// </summary> /// <returns></returns> public ActionResult Edit(int id) { var user = db.UserInfos.Find(id); return View(user); } /// <summary> /// 編輯用戶處理 /// </summary> /// <returns></returns> [HttpPost] public ActionResult Edit(UserInfo user) { try { if (ModelState.IsValid) { db.Entry(user).State = EntityState.Modified; db.SaveChanges(); return RedirectToAction("Index"); } else { throw new Exception(); } } catch (Exception ex) { ModelState.AddModelError("", "更改失敗"); } return View(user); } /// <summary> /// 刪除操作處理 /// </summary> /// <returns></returns> public ActionResult Delete(int id) { var user = db.UserInfos.Find(id); db.UserInfos.Remove(user); db.SaveChanges(); return RedirectToAction("Index"); } } }
新加的代碼做一個簡單解析。
var user = db.UserInfos.Find(id);的意思是根據傳過來的用戶id查找對應用戶;
db.UserInfos.Remove(user);的意思是移除用戶
按照我們的一般思維邏輯,刪除操作一般在列表頁實現,通常會有一個確認刪除的提示,現在我們修改UserInfo/Index.cshtml代碼,添加刪除鏈接和確認刪除的提示js,完整代碼如下:
@model IEnumerable<MyShopTest.Models.UserInfo> @{ ViewBag.Title = "用戶列表"; } <script type="text/jscript"> function confirmDel(itemId) { if (confirm("確認刪除嗎?")) { window.location.href = "/UserInfo/Delete/" + itemId; } } </script> <h2> 用戶列表</h2> <p> <a href="/UserInfo/Create">添加用戶</a> </p> <table> <tr> <th> 用戶名 </th> <th> 電話 </th> <th> 郵箱 </th> <th> 注冊時間 </th> <th> 操作 </th> </tr> @foreach (var item in Model) { <tr> <td> @item.UserName </td> <td> @item.Phone </td> <td> @item.Email </td> <td> @item.AddTime </td> <td> @Html.ActionLink("編輯", "Edit", new { id=item.Id}) <a href="javascript:void(0);" onclick="confirmDel(@item.Id);">刪除</a> </td> </tr> } </table>
這些代碼里,沒有新知識,因此不做解析。重新編譯項目,運行,進入用戶管理。
點擊刪除,可以看到確認刪除的提示

點擊確定,刪除操作完成

現在我們已經基本完成了用戶的刪除操作,但是有些時候當用戶數據很多的時候,我們更期望進行批量刪除操作,這也是在傳統的B/S應用程序里經常遇到的,現在我們再來為用戶管理,添加批量刪除功能,同時保留剛才的逐項刪除,以幫助大家理解代碼,修改UserInfo控制器,添加批量刪除的處理Action,完整代碼如下:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using MyShopTest.Models; using System.Data; namespace MyShopTest.Controllers { public class UserInfoController : Controller { //數據訪問 private MyShopDataEntities db = new MyShopDataEntities(); /// <summary> /// 用戶列表Action /// </summary> /// <returns></returns> public ActionResult Index() { var users = db.UserInfos.ToList(); return View(users); } /// <summary> /// 添加用戶頁面展示 /// </summary> /// <returns></returns> public ActionResult Create() { return View(); } /// <summary> /// 添加用戶處理 /// </summary> /// <returns></returns> [HttpPost] public ActionResult Create(UserInfo user) { db.UserInfos.Add(user); db.SaveChanges(); return RedirectToAction("Index"); } /// <summary> /// 編輯用戶頁面展示 /// </summary> /// <returns></returns> public ActionResult Edit(int id) { var user = db.UserInfos.Find(id); return View(user); } /// <summary> /// 編輯用戶處理 /// </summary> /// <returns></returns> [HttpPost] public ActionResult Edit(UserInfo user) { try { if (ModelState.IsValid) { db.Entry(user).State = EntityState.Modified; db.SaveChanges(); return RedirectToAction("Index"); } else { throw new Exception(); } } catch (Exception ex) { ModelState.AddModelError("", "更改失敗"); } return View(user); } /// <summary> /// 刪除操作處理 /// </summary> /// <returns></returns> public ActionResult Delete(int id) { var user = db.UserInfos.Find(id); db.UserInfos.Remove(user); db.SaveChanges(); return RedirectToAction("Index"); } /// <summary> /// 批量刪除操作處理 /// </summary> /// <param name="coll"></param> /// <returns></returns> [HttpPost] public ActionResult Deletes(FormCollection coll) { string ids = coll["ckSelect"]; foreach (var item in ids.Split(','))//循環每一項Id { if (item != "false")//篩選掉自動生成的checkbox初始值 { var user = db.UserInfos.Find(Convert.ToInt32(item)); db.UserInfos.Remove(user); } } db.SaveChanges(); return RedirectToAction("Index"); } } }
解析一下新增代碼,
參數(FormCollection coll),這是獲取提交過來的表單值集合
string ids = coll["ckSelect"];獲取表單中name是ckSelect的所有表單值,獲取到的是英文逗號分隔的一個數組
foreach (var item in ids.Split(','))循環每一個值
if (item != "false")//篩選掉自動生成的checkbox初始值,因為我們前台使用了 @Html.CheckBox來生成復選框,而這個方法在生成復選框時會默認生成該復選框的一個Hidden標簽,用來保存該復選框的初始狀態,詳見接下來的視圖頁面注解。
現在,我們修改視圖頁面以實現批量刪除,仍是修改Index.cshtml,完整代碼如下:
@model IEnumerable<MyShopTest.Models.UserInfo> @{ ViewBag.Title = "用戶列表"; } <script src="../../Scripts/jquery-1.5.1-vsdoc.js" type="text/javascript"></script> <script type="text/jscript"> function confirmDel(itemId) { if (confirm("確認刪除嗎?")) { window.location.href = "/UserInfo/Delete/" + itemId; } } function selectAll() { var checked = $("#ckAll").attr("checked"); $("input[name='ckSelect']").attr("checked", checked); if (checked) { $("#spInfo").html("反選"); } else { $("#spInfo").html("全選"); } } function delIds() { if (confirm("確認要刪除選中數據嗎?")) { var checkedCount = $("input[name='ckSelect']:checked").length; if (checkedCount>0) { $("form").first().submit(); //提交表單 } else { alert("請先選擇操作項!"); } } } </script> <h2> 用戶列表</h2> @using (Html.BeginForm("Deletes", "UserInfo", FormMethod.Post)) { <p> <a href="/UserInfo/Create">添加用戶</a> <input type="button" onclick="delIds();" value="批量刪除" /> </p> <table> <tr> <th> <input type="checkbox" name="ckAll" id="ckAll" onclick="selectAll();" /><span id="spInfo">全選</span> </th> <th> 用戶名 </th> <th> 電話 </th> <th> 郵箱 </th> <th> 注冊時間 </th> <th> 操作 </th> </tr> @foreach (var item in Model) { <tr> <td> <!--此方法生成的復選框,會默認生成一個對應的hidden,用來保存初始狀態,此方法參數意義是,名稱,初始選中狀態,html屬性--> @Html.CheckBox("ckSelect", false, new { value = item.Id }) </td> <td> @item.UserName </td> <td> @item.Phone </td> <td> @item.Email </td> <td> @item.AddTime </td> <td> @Html.ActionLink("編輯", "Edit", new { id = item.Id }) <a href="javascript:void(0);" onclick="confirmDel(@item.Id);">刪除</a> </td> </tr> } </table> }
我們添加了一些js代碼,用以實現全選和確認刪除,我們頭部引用了
<script src="../../Scripts/jquery-1.5.1-vsdoc.js" type="text/javascript"></script>這是為了實現在vs下的jquery的智能提示,jquery引用類庫,其實是在母版頁里。
重新編譯項目,運行,用戶管理,自行添加幾條測試數據:
右鍵,查看源文件,我們可以看到 @Html.CheckBox生成有隱藏域保存初始狀態
我們來測試一下全選效果:
我們去掉一項,准備執行刪除
點擊批量刪除,會彈出提示是否確認
點擊確認,完成批量刪除
至此,我們已經完成了用戶的批量刪除功能。
2.實現用戶數據的初始化以及當實體發生改變時自動更改數據庫
上一章里我們給用戶信息添加驗證時,重新編譯項目運行時項目出錯了,提示實體已經改動,我們當時為了測試方便的做法是,直接刪除了原有數據庫,重新讓系統創建的。雖然當時解決了問題,但是這種做法有諸多不足,比如當項目已經進行到了相當的程度,或者項目里已經有不少的測試數據了,而且測試數據的關聯性又比較強,這時候我們再清除數據就相當麻煩了,但是在實際的項目開發中,用戶變更需求,或者程序員由於當時的設計不夠健壯,后續改動實體模型和數據庫結構的情況很多,那么怎么才能避免這種情況,使得數據庫即使重建了也能保留好我們的測試數據,或者干脆在實體發生改動時就自動重構數據庫呢。接下來我們就來實現這個功能。
右鍵Models文件夾,添加類,命名為InitData,修改完整代碼如下:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Data.Entity; using System.Data.Entity.Validation; namespace MyShopTest.Models { public class InitData : DropCreateDatabaseIfModelChanges<MyShopDataEntities> { //實體發生改變時,重新創建數據庫,首次也會運行此處 protected override void Seed(MyShopDataEntities context) { try { //初始化數據 var users = new List<UserInfo> { new UserInfo { UserName = "admin",UserPwd="admin",AddTime=DateTime.Now,Email="Qq@qq.com",Phone="13112345678" }, new UserInfo { UserName = "zhangsan",UserPwd="admin",AddTime=DateTime.Now,Email="Qq@qq.com",Phone="13112345678" }, new UserInfo { UserName = "lisi",UserPwd="admin",AddTime=DateTime.Now,Email="Qq@qq.com",Phone="13112345678" } }; users.ForEach(user => context.UserInfos.Add(user)); } catch (DbEntityValidationException dbEx) { string a = dbEx.Message; } } } }
我們來解析一下代碼:
public class InitData : DropCreateDatabaseIfModelChanges<MyShopDataEntities>
這句代碼的意思是該類繼承於DropCreateDatabaseIfModelChanges,DropCreateDatabaseIfModelChanges是當實體改變時重新構建數據庫的類,它指明的數據庫操作類是我們建立好的MyShopDataEntities,這樣當實體發生變化時程序才知道根據哪個類去操作數據庫。
//實體發生改變時,重新創建數據庫,首次也會運行此處 protected override void Seed(MyShopDataEntities context) { try { //初始化數據 var users = new List<UserInfo> { new UserInfo { UserName = "admin",UserPwd="admin",AddTime=DateTime.Now,Email="Qq@qq.com",Phone="13112345678" }, new UserInfo { UserName = "zhangsan",UserPwd="admin",AddTime=DateTime.Now,Email="Qq@qq.com",Phone="13112345678" }, new UserInfo { UserName = "lisi",UserPwd="admin",AddTime=DateTime.Now,Email="Qq@qq.com",Phone="13112345678" } }; users.ForEach(user => context.UserInfos.Add(user)); } catch (DbEntityValidationException dbEx) { string a = dbEx.Message; } }
我們重寫了DropCreateDatabaseIfModelChanges里的Seed方法,這個方法表明我們要初始化的數據,此處我們用三個用戶組成了一個集合,然后一一計入了數據庫。
到此處,我們寫的實體發生改變時初始化的數據已經完成了,我們還需要告訴程序什么時候執行這一個類,這就需要用到Global,雙擊打開Global.asax.cs,修改完整代碼如下:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using System.Web.Routing; using MyShopTest.Models; namespace MyShopTest { // 注意: 有關啟用 IIS6 或 IIS7 經典模式的說明, // 請訪問 http://go.microsoft.com/?LinkId=9394801 public class MvcApplication : System.Web.HttpApplication { public static void RegisterGlobalFilters(GlobalFilterCollection filters) { filters.Add(new HandleErrorAttribute()); } public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( "Default", // 路由名稱 "{controller}/{action}/{id}", // 帶有參數的 URL new { controller = "Home", action = "Index", id = UrlParameter.Optional } // 參數默認值 ); } protected void Application_Start() { //System.Data.Entity.Database.SetInitializer<MyShopDataEntities>(null);//此段代碼實現同時修改表和類中字段,而數據不動。 System.Data.Entity.Database.SetInitializer(new InitData());//此段代碼實現重新根據新實體模型構建數據庫,同時初始化數據 AreaRegistration.RegisterAllAreas(); RegisterGlobalFilters(GlobalFilters.Filters); RegisterRoutes(RouteTable.Routes); } } }
添加了兩行代碼,注釋應該已經說的很清楚了,在此不再解析,為了測試效果,我們修改Models/UserInfo的屬性Phone,將它變為不必必須輸入,修改后完整代碼如下:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.ComponentModel.DataAnnotations; namespace MyShopTest.Models { public class UserInfo { [ScaffoldColumn(false)] public int Id { get; set; } [Display(Name="用戶名")] [Required(ErrorMessage="必須輸入用戶名!")] public string UserName { get; set; } [Display(Name = "密碼")] [Required(ErrorMessage = "必須輸入密碼!")] [StringLength(8, MinimumLength = 3, ErrorMessage = "密碼長度必須是3到8個字符之間")] public string UserPwd { get; set; } [Display(Name = "電話")] [RegularExpression(@"((\d{11})|^((\d{7,8})|(\d{4}|\d{3})-(\d{7,8})|(\d{4}|\d{3})-(\d{7,8})-(\d{4}|\d{3}|\d{2}|\d{1})|(\d{7,8})-(\d{4}|\d{3}|\d{2}|\d{1}))$)",ErrorMessage="電話格式不正確")] public string Phone { get; set; } [Display(Name = "郵箱")] [RegularExpression(@"\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*", ErrorMessage = "郵箱格式不正確")] public string Email { get; set; } private DateTime addTime; [Display(Name="注冊時間")] [Required()] public DateTime AddTime { get { if (addTime == null) { return DateTime.Now; } return addTime; } set { addTime = value; } } } }
重新編譯項目,運行,看一下測試效果
初始化數據已經添加了,測試成功