MVC3学习第八章 葵花点穴手之指如疾风----MVC3下实现数据的批量删除和利用EF初始化我们的数据

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})
                &nbsp;
                <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>&nbsp;
        <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 })
                    &nbsp; <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; }
        }
    }
}

重新编译项目,运行,看一下测试效果

初始化数据已经添加了,测试成功

 

 
posted @ 2013-06-24 15:00  韩若怅  阅读(841)  评论(8编辑  收藏  举报