admin 管理员组

文章数量: 1086019


2023年12月18日发(作者:c2059 语法错误)

MVC3+EF4.1学习系列(六)-----导航属性数据更新的处理

Admin

2011年8月1日 名人名言:书,这是这一代人对另一代人精神上的遗言,这是将死的老人对刚刚开始生活的青年人的忠告,这是准备去休息的哨兵对前来代替他的岗位的哨兵的命令。——赫尔岑

文章索引和简介

通过上一篇的学习 我们已经知道怎么查询关系 这篇就来说说怎么导航属性数据更新时的处理 以及EF又会为我们生成哪些SQL~

老规矩 先看下今天的图

添加和修改页面基本就是这样

这节的内容相对简单~~

主要就是讲 一对一 一对多 多对多时的增删改 以及MVC的一些小东西

一. 一对多的的处理

看第一张图 院系和课程是一对多的关系

1.添加

一对多的添加非常简单 遇到一对多的情况 我们一般考虑dropdownlist来展示 只要把这个展示出来就容易了

mvc绑定dropdownlist 一般是 控制器用 viewstate存一个SelectList 或者viewbag 然后视图绑定 上代码

课程添加控制器

public ActionResult Create()

{ PopulateDepartmentsDropDownList(); return View(); }

// // POST: /Course/Create [HttpPost] public ActionResult Create(Course course) { try { // TODO: Add

logic here if (d)

{ (course); anges();

// PopulateDepartmentsDropDownList(mentID); }

return RedirectToAction("Index"); } catch

{ elError("", "Unable to save changes. Try again, and

if the problem persists, see your system administrator."); return View(); } } ///

/// 处理下拉列表

///

/// 选择的项 private void

PopulateDepartmentsDropDownList(object ed = null) { var

departmentsQuery = d in ments orderby

d; mentID =

new SelectList(departmentsQuery, "DepartmentID", "Name", ed); }

可以看到 非常简单下面是视图的

视图

@model @{ = "Create"; Layout =

"~/Views/Shared/_";}

Create

@using

(orm()) { @tionSummary(true)

Course

@or(model => ID)

@For(model => ID) @tionMessageFor(model => ID)

@or(model => )

@For(model => ) @tionMessageFor(model =>

@or(model => s)
@For(model => s) @tionMessageFor(model =>

s)

@or(model => mentID, "Department")

class="editor-field"> @wnList("DepartmentID","请选择")

@tionMessageFor(model => mentID)

}
@Link("Back to List", "Index")

视图的核心其实就这句

wnList("DepartmentID","请选择")

DepartmentID 对应 你的viewbag 就能让他们对应上去了 就这么简单神奇~~ 由于生成的html name 为 DepartmentID 当你保存的时候 通过ModelBinder 会自动对应到实体类上 直接保存即可 生成的SQL插入语句也简单 而且是参数化的~

exec s p_executesql N"" [dbo].[Course]([CourseID], [Title], [Credits], [DepartmentID])values

(@0, @1, @2, @3)"",N""@0 int,@1 nvarchar(50),@2 int,@3 int"",@0=4444,@1=N""试试插入"",@2=4,@3=1

2.修改

这个没啥好说的了~~ 基本和添加一样

修改控制器

public ActionResult Edit(int id) { Course course = (id);

PopulateDepartmentsDropDownList(mentID); return View(course); } // // POST: /Course/Edit/5 [HttpPost]

public ActionResult Edit(Course course) { try

{ if (d)

{ (course).State = ed;

anges(); return RedirectToAction("Index"); } } catch (DataException)

{ //Log the error (add a variable name after DataException)

elError("", "Unable to save changes. Try again, and if the problem persists,

see your system administrator."); }

PopulateDepartmentsDropDownList(mentID); return View(course); }

生成的SQL语句如下

exec s p_executesql N"" [dbo].[Course]set [Title] = @0, [Credits] = @1, [DepartmentID] = @2where ([CourseID] = @3)"",N""@0 nvarchar(50),@1 int,@2 int,@3 int"",@0=N""试试插入"",@1=4,@2=2,@3=4444

这有个问题 就是把每个字段都做了更新 而我们实际上只更新了一个 如果能按需更新改多好 dudu给了我们好的思路 可以参考下 -----文章连接

3.删除

这个简单....没啥好说的了 具体参考第二篇 简单的增删改查~~

二.一对一和多对多

一对多比较简单 因为涉及的都是一张表里的东西 所以没什么难的 而一对一,多对多 则是处理 多张表的情况 所以这里重点说下这部分~~

先看第二个图 分析下关系 这是修改老师的信息 跟他关联的有一对一的地址 和多对多的课程 也就是说 当我们插入一条记录时

应该插入三张表 教师表 办公地址表 和 教师课程关系表 那让我们来印证下吧

1.添加

首先 我们要先把添加页面显示出来 先来说下 下面那个复选框选择课程 控制器很简单

就是读取出来所有课程存放到viewbag里即可

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

视图的显示 有两种方法 一种是原文提供的

添加一个viewmodel 专门存放课程 以及是否选中 然后通过如下代码实现三列换行

原文的方法

@{ int cnt = 0;

List courses = s;

foreach (var course in courses) { if (cnt++ % 3 == 0)

{ @:

}

@:

} @: }

name="edCourses" value="@ID"

@((ed ? "checked="checked"" : "")) />

@ID @:  @

@:

个人觉得麻烦了些 这里我说下我的方法

@{ Builder sb = new

Builder("

");

List<> list= Course as

List<>; for (int i = 0; i < ; i++)

{ if (i!=0&&i % 3 == 0)

{ ("

"); }

("

"); } ("

name=""edCourses""/>"+list[i].Title+"

"); } @(ng())

这里要说的就是 如果不使用这个 直接输入 则会把 这些也直接输入出来 而不是转换成HTML 记住,如果想生成想要的结果 请使用

好了 添加页面有了 现在就是添加了

添加

[HttpPost] public ActionResult Create(Instructor Model, string[] edCourses)

{ try { // TODO: Add logic here

if (d) { s = new

List();

{

{

(item);

if

foreach (var item in ())

(ns(ng()))

} }

(Model); anges(); } return RedirectToAction("Index"); } catch

{ return View(); } }

这里提下 第二个参数 就是我们选中的checkbox 的value 的集合 这个参数的名字 与

checkbox名字的name一样

然后我们遍历所有的课程 把符合条件的加入进来 我选了一个 让我们看下EF为我们生成的SQL

exec s p_executesql N"" [dbo].[Instructor]([LastName], [FirstName], [HireDate])values (@0, @1, @2) [InstructorID] [dbo].[Instructor]where @@ROWCOUNT > 0 and [InstructorID]

= scope_identity()"",N""@0 nvarchar(50),@1 nvarchar(50),@2 datetime"",@0=N""W"",

@1=N""LF"",@2=""02 3 2011 12:00:00:000AM""exec s p_executesql N""

[dbo].[CourseInstructor]([CourseID], [InstructorID])values (@0, @1)"",N""@0 int,@1 int"",@0=2042,@1=10exec s p_executesql N"" [dbo].[OfficeAssignment]([InstructorID],

[Location])values (@0, @1)"",N""@0 int,@1 nvarchar(50)"",@0=10,@1=N""天朝""

看 确实是生成了三条SQL语句 符合我们的要求 而我们的代码 却写了很少 就轻松完成了添加~~

2.修改

修改要比添加麻烦 首先显示视图时 要显示哪些被选中了 还有就是修改时 要在关系表里删除原来的 课程教师关系 还要添加新的进去

如何让EF帮我们完成这一对一 多对多的复杂的 三张表之间的关系处理呢

还是先从视图开始 先解决让以前被选中的显示出来

public ActionResult Edit(int id) { Course =

(); Instructor model= e(i =>

s).Include(i => Assignment).Where(i => ctorID == id).SingleOrDefault(); return View(model); }

先把要修改的这条加载出来返回给视图 用贪婪加载 把地点和课程都加载出来

修改视图

@{ Builder sb = new

Builder("

");

List<> list= Course as

List<>; for (int i = 0; i < ; i++)

{ if (i!=0&&i % 3 == 0)

{ ("

"); } string

IsSelect = ; if (ns(list[i]))

{ IsSelect = "checked=""checked"""; }

("

"); } ("

name=""edCourses""/>"+list[i].Title+"

"); } @(ng())

在视图上加上判断 遍历到的这个课程 是否在选中的课程里 如果在 则加上选中属性

string IsSelect = ; if (ns(list[i]))

{ IsSelect = "checked=""checked"""; }

这样就解决了视图修改时的显示问题了 下面是点击修改时 让我们先大概想想 有哪些操作

1.修改 教师表信息

2.修改 地址表信息

3. 删除以前的课程关系表 和添加新的课程关系表记录

这里比较负责的是第三部 我们来想想怎么做 现在 我们能知道 我们新选择了哪些 和

以前选择了哪些 比如 新选择的是 {1,2,3} 这次选的是 {3,4,5} 那么我们应该

删除{4,5} 添加{1,2} 即可 这其实就转换为一个简单的算法题了~~ 原文给出了一种方法

我自己也写了一种 大家可以比较下看~先上原文的

原文修改核心代码

private void UpdateInstructorCourses(string[] edCourses, Instructor instructorToUpdate){ if

(edCourses == null) { s = new List();

return; } var edCoursesHS = new HashSet(edCourses); var

instructorCourses = new HashSet ((c =>

ID)); foreach (var course in s) { if (ns(ng())) { if (!ns(ID)) { (course); } } else { if

(ns(ID))

{

(course); } } }}

原文利用HashSet 不能存重复项 实现 不过判断逻辑多了些 但效率应该高 hashset 散列算法

下面是我的

private void UpdateInstructorCourses(string[] edCourses, Instructor instructor)

{ if (edCourses == null) { s =

new List(); return; } //思路 比较以前选择的和现在选择的 先取出他们的差集 那么这部分就是可以删除的项 和添加的部分

string[] beforeSelect=(i => ng()).ToArray();//得到以前选择的 (edCourses).ToList().ForEach(n =>

((32(n))));

(beforeSelect).ToList().ForEach(n => ((32(n)))); }

这里 参数edCourses 为现在选中的项 利用linq 内置的方法 Except取出差集 然后

ForEach遍历移除和添加 一句话搞定 但是效率估计不会太高~~

下面是完整的修改方法

完整修改方法

[HttpPost] public ActionResult Edit(int id, FormCollection collection, string[]

edCourses) { try { // TODO: Add logic

here var instructor = e(i => s).Where(i =>

ctorID == id).SingleOrDefault(); UpdateModel(instructor, "", null,

new string[] {"Courses"}); UpdateInstructorCourses(edCourses, instructor);

if (OrWhiteSpace(on))

{ Assignment = null; }

(instructor).State = ed; anges();

return RedirectToAction("Index"); } catch

{ return View(); } } private void

UpdateInstructorCourses(string[] edCourses, Instructor instructor) { if

(edCourses == null) { s = new List(); return; } //思路 比较以前选择的和现在选择的 先取出他们的差集 那么这部分就是可以删除的项 和添加的部分

string[] beforeSelect=(i => ng()).ToArray();//得到以前选择的 (edCourses).ToList().ForEach(n =>

((32(n))));

(beforeSelect).ToList().ForEach(n => ((32(n)))); }

好了 让我们来看下执行的SQL

exec s p_executesql N"" [dbo].[Instructor]set [LastName] = @0, [FirstName] = @1, [HireDate]

= @2where ([InstructorID] = @3)"",N""@0 nvarchar(50),@1 nvarchar(50),@2 datetime,@3 int"",@0=N""W"",@1=N""LF"",@2=""02 3 2011 12:00:00:000AM"",@3=10exec s

p_executesql N"" [dbo].[OfficeAssignment]set [Location] = @0where ([InstructorID] = @1)"",N""@0 nvarchar(50),@1 int"",@0=N""超"",@1=10exec s p_executesql N""

[dbo].[CourseInstructor]where (([CourseID] = @0) and ([InstructorID] = @1))"",N""@0 int,@1 int"",@0=2042,@1=10exec s p_executesql N"" [dbo].[CourseInstructor]([CourseID],

[InstructorID])values (@0, @1)"",N""@0 int,@1 int"",@0=0,@1=10

看 和我们想要的效果一样~~

3.删除

简单的说下删除, 当我们删除一条数据时 直接看生成的SQL语句 预计应该是 要删3个

exec s p_executesql N"" [dbo].[CourseInstructor]([CourseID], [InstructorID])values (@0,

@1)"",N""@0 int,@1 int"",@0=0,@1=10exec s p_executesql N""

[dbo].[OfficeAssignment]where ([InstructorID] = @0)"",N""@0 int"",@0=10

结果是删除了 2个表的 一对一的删除了 可是多对多的为什么没删除 这其实是一个简单的数据库知识了~~

EF为我们创建数据库时 这个删除规则是层叠 就是级联删除 所以这个关系表的就会被直接删除了

三.总结

导航属性的更新操作等 结束了 现在EF的已经基本操作已经结束了 下一节讲EF处理并发的策略


本文标签: 课程 修改 添加 关系 删除