zoukankan      html  css  js  c++  java
  • MVC5+EF6 入门完整教程10 数据查询更新

    关联数据更新有两种情况:

    1.一对多

    2.多对多

    第一种情况关联表有主外键关联,只要简单的更新外键值就可以了(相当于更新单表),我们主要讲解第二种多对多的情况。

    使用之前很熟悉的模型:

    我们定义一个场景:    

    一个用户可以有任意多个角色,一个角色可以有任意多个用户。

    我们接下来完成下面操作:

    编辑某个用户时,显示该用户的角色进行编辑。

    即 更新某个用户(SysUser表)及其相关的角色(SysUserRole表)。

    详细步骤:

    1.先添加一个ViewModel, 用来表示角色是否分配给某个用户。

    2.打开UserRoleController,添加一个Edit的Action用来显示编辑页面。

    PopulationRoles:将该用户具有的角色存在ViewBag.assignedRole

            private void PopulationRoles(User user)
            {
                var allRoles = db.Roles.ToList();
                var userRoleIDs = new HashSet<int>(user.UserRoles.Select(m => m.RoleID));
                var assignedRole = new List<AssignedRoleData>();
                foreach (var role in allRoles)
                {
                    assignedRole.Add(
                        new ViewModels.AssignedRoleData
                        {
                            RoldId = role.ID,
                            RoldName = role.RoleName,
                            Assigned = userRoleIDs.Contains(role.ID)
                        });
                }
                ViewBag.assignedRole = assignedRole;
            }
    

      

    PopulationDepartmentDropDownList:将该用户部门信息存在ViewBag.DepartmentDropDownList

            private void PopulationDepartmentDropDownList(User user)
            {
                // 部门信息
                var allDepartments = db.Departments.ToList();
                ViewBag.DepartmentDropDownList = new SelectList(allDepartments, "id", "name", user.DepartmentID);
                return;
            }
    

      

            public ActionResult Edit(int? id)
            {
                if (id == null)
                {
                    return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
                }
                IQueryable<User> users = db.Users
                    .Include("Department")
                    .Include("UserRoles")
                    .Where(u => u.ID == id);
    
                if (users.Count() < 1) return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
                User user = users.Single();
                PopulationRoles(user);
                PopulationDepartmentDropDownList(user.DepartmentID);
                if (user == null)
                {
                    return HttpNotFound();
                }
                return View(user);
            }
         public ActionResult Index(int? id)
            {
                var viewModel = new UserAndUserRole();
                viewModel.Users = db.Users
                    .Include("Department")
                    .Include("UserRoles")
                .OrderBy(u => u.UserName).ToList();
    
                if (id != null)
                {
                    ViewBag.UserID = id.Value;
                    // 按照用户ID选择1个用户,在选择该用户的UserRoles
                    IEnumerable< User> users = viewModel.Users.Where(u => u.ID == id.Value);
                    if (users.Count<User>()>0) //用户存在
                    {
                        viewModel.UserRoles = users.Single().UserRoles;//该用户的角色 IEnumerable
                        viewModel.Roles = (viewModel.UserRoles.Where(ur => ur.UserID == id.Value)).Select(ur => ur.Role);
                    }
                }
                return View(viewModel);
            }

     3.打开ViewsUserRoleIndex.cshtml, 增加一个编辑按钮

                <td>
                    @{
                        foreach (var userRole in item.UserRoles)
                        {
                            @userRole.Role.RoleName <br />
                        }
                    }
                </td>
                <td>
                    @Html.ActionLink("Select", "Index", new { id = item.ID }) |
                    @Html.ActionLink("Edit", "Edit", new { id = item.ID })
                </td>
    

      

    4.再根据Edit Action自动生成Edit View

    修改相关内容,主要是两点:

    a.部门  后台向前台传DropDownList信息

            <div class="form-group">
                @Html.LabelFor(model => model.DepartmentID, null, htmlAttributes: new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @Html.DropDownList("DepartmentID", ViewBag.DepartmentDropDownList as SelectList, htmlAttributes: new { @class = "form -control" })
                    @Html.ValidationMessageFor(model => model.DepartmentID, "", new { @class = "text-danger" })
                </div>
            </div>
    

      

     b.角色  checkbox显示

            <div class="form-group">
                <div class="col-md-offset-2  col-md-10">
                    <table>
                        <tr>
                            @{ 
                                List<AssignedRoleData> roles = ViewBag.assignedRole;
                                foreach (var role in roles)
                                {
                                    <td>
                                        <input type="checkbox" name="selectedRoles" value="@role.RoldId" 
                                               @(Html.Raw(role.Assigned ? "checked="checked"" : ""))/> 
                                       @role.RoldName
                                    </td>
                                }
    
                            }
                        </tr>
                    </table>
                </div>
            </div>
    

      

     运行下Index页面。

    进入编辑页面。

    5.最后再完成HttpPost的Edit功能。

    首先更新User表:

    用model binder中的值更新entity: userToUpdate.

    可以看到,我们使用了白名单指定数据库中需要更新的字段。

    TryUpdateModel(userToUpdate,"",

    new string[] {"LoginName","Email","Password","CreateDate","SysDepartmentID"})

    再更新SysUserRole表:

    将数据库中值和编辑后的值进行比对,基本逻辑是:

    如果被选中了,原来没有的要添加;

    如果没被选中,原来有的要删除。

    UpdateUserRoles(selectedRoles, userToUpdate);

            [HttpPost]
            public ActionResult Edit(int? id, string[] selectedRoles) //selectedRoles  view中的名称
            {
                if (id == null)
                {
                    return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
                }
    
                var  userToUpdate = db.Users
                    .Include("UserRoles")
                    .Where(u => u.ID == id)
                    .Single();
                // 显式模型绑定 :将form返回的UserName,Email,Password,CreateDate,DepartmentID值显示绑定到模型实体userToUpdate
                if (TryUpdateModel(userToUpdate,"",new string[] {"UserName","Email","Password","CreateDate","DepartmentID"}))
                {
                    try
                    {
                        UpdateUserRoles(selectedRoles, userToUpdate);
                        db.Entry(userToUpdate).State = System.Data.Entity.EntityState.Modified;
                        db.SaveChanges();
                        return RedirectToAction("Index");
                    }
                    catch (Exception e)
                    {
                        throw;
                    }
                }
                PopulationDepartmentDropDownList(userToUpdate);
                PopulationRoles(userToUpdate);
                return View(userToUpdate);
            }
    

      

            private void UpdateUserRoles(string[] selectedRoles, User userToUpdate)
            {
                // 没有选择角色,全部清空
                if (selectedRoles == null)
                {
                    //用户原有角色
                    foreach (var item in userToUpdate.UserRoles.ToList())
                    {
                        db.UserRoles.Remove(item);
                    }
                    db.SaveChanges();
                }
                else
                {
                    //选中的角色
                    var selectedRolesHS_String = new HashSet<string>(selectedRoles);
                    //原来的角色
                    var oldRolesHS_Int = new HashSet<int>(userToUpdate.UserRoles.Select(r => r.RoleID));
    
                    foreach (var role in this.db.Roles.ToList()) //比较所有的角色
                    {
                        if (selectedRolesHS_String.Contains(role.ID.ToString()))//该角色选中
                        {
                            if (!oldRolesHS_Int.Contains(role.ID))//原来没有选中
                            {
                                UserRole userRole = new UserRole { UserID = userToUpdate.ID, RoleID = role.ID };
                                db.UserRoles.Add(userRole);
                                db.SaveChanges();
                            }
                        }
                        else  //该角色没有选中
                        {
                            if (oldRolesHS_Int.Contains(role.ID))//原来选中
                            {
                                UserRole userRole = db.UserRoles.FirstOrDefault(u => u.RoleID == role.ID && u.UserID == userToUpdate.ID);
                                db.UserRoles.Remove(userRole);
                                db.SaveChanges();
                            }
                        }
    
                    }
                }
            }
    

      

    重新运行下Index, 如下一组图,这时我们看到角色编辑已经起作用了。

    至此,多表更新的示例就介绍到这,其他情况相信你可以举一反三自己推导出来做法。

    使用原生SQL

    使用EF的一个优点就是自动帮我们生成SQL,这在常规情况下很方便,但有些情况下用EF却不适合。

    例如我们上面更新SysUserRole这张表时,每次增减一条数据,要循环很多次。

    另外还有些特别复杂的语句,利用EF很难生成。

    EF提供一组方法用来执行原生的SQL.

    有以下三种:

     

    例子1:DbSet.SqlQuery查询并返回Entities

    我们打开ControllersAccountController.cs做实验

    找到Details方法

    将注释的部分改成方框部分即可。

    方框中的和注释掉的内容User user=db.Users.Find(id)完全一样。

    前端显示效果不变:

     点击详细信息:

    注意两点:

    1.构造带参数的SQL语句(养成好习惯,防止SQL注入,总是用带参数的SQL语句)

    2.此处使用的是DbSet<TEntity>执行SQL方法,返回的直接是Entity, 和LINQ查询一样。如果暂时不熟悉LINQ,用这种方法替换(作为一个过渡),可以让你快速的使用起新框架。

    这种情况有一些缺陷,例如

    SELECT LoginName as UserName,* FROM [dbo].[SysUser] WHERE ID=@id

    大家可以看到我添加了LoginName as UserName,这是因为Model中用了Column Attribute,数据库中存的字段是LoginName

    这样我如果不转换,model就会找不到匹配的字段而出错,而如果用db.SysUsers.Find(id) 就可以智能转换。

    例子2 Database.SqlQuery 返回其他类型

    string query = "select loginName from User";

    var names=db.Database.SqlQuery<string>( query).ToList();

    以上会返回一个System.Collections.Generic.List<string>类型。

    这种方式和第一种情况最大的区别就是返回non-entity 类型。

    我们可以根据需要,自己构建需要的类型。

    我们也可以自定义一个entity type让它返回,例如类似我们上一个例子:

    User user = db. Database.SqlQuery(query, paras).SingleOrDefault();

    这样也可以返回entity, 但要注意,这种方式将不会被context track, 返回后就没关系了,如果我们在View中用类似于Model.XXX导航属性获取其他关联数据就会报错。例如@foreach (var item in Model.UserRoles),这种情况下会报Model为null的错误。

    例子3:Database.ExecuteSqlCommand执行更新语句

    最后一个是更新的,直接看示例就明白了:

    context.Database.ExecuteSqlCommand("UPDATE dbo.Posts SET Rating = 5 WHERE Author = @author", new SqlParameter("@author", userSuppliedAuthor));

    EF6 :  https://docs.microsoft.com/zh-cn/ef/ef6/

    最后提下执行存储过程,也类似,我就不多说了,如下MSDN(https://msdn.microsoft.com/en-us/data/jj592907)截图。

    原生SQL使用总结     https://docs.microsoft.com/zh-cn/ef/ef6/querying/raw-sql

    原生SQL执行查询:

    需要返回实体模型,使用DbSet.SqlQuery (context会跟踪,等效于LINQ方式)

    需要返回其他类型,使用Database.SqlQuery

    原生SQL执行更新:

    使用Database.ExecuteSqlCommand

  • 相关阅读:
    [人物存档]AI【捏脸数据】【捏人数据】【人物卡精选】少女3DCG设计参考萌萌的耳朵
    [人物存档]AI【捏脸数据】【捏人数据】【人物卡精选】少女3DCG设计参考
    碧蓝航线-cosplay-吾妻猉 绘画CG设计参考
    Pixiv日榜2020-4-5精选动漫插画壁纸 设计参考
    Marvelous Designer 旗袍设计参考素材免费分享及服装3D模型导入MD教程
    [人物存档]AI【捏脸数据】【捏人数据】【人物卡精选】少女设计参考
    P站日榜【2020-3-22】pixiv动漫美图热门插画壁纸
    Pixiv腿部渔网袜绘画设计参考特辑,在我眼里你就是一个弟弟(姐弟特辑)绘画参考
    Daz3D studio 快速上手进阶免费教程,持续更新
    Airflow 1.10安装
  • 原文地址:https://www.cnblogs.com/wfy680/p/14277546.html
Copyright © 2011-2022 走看看