把ContosoUniversity例子过了一遍,好象还是有很多东西未能理解,决定自己随便加个功能看可以自己完成不....
从github的例子中clone下来ContosoUniversity项目,使用CodeFirst进行迁移后就可以得到一个正常运作的例子。
增加的课程计划 StudentCoursePlan.cs
public partial class StudentCoursePlan { public int Id { get; set; } public int CourseId { get; set; } public int StudentId { get; set; } public Student Student { get; set; } public Course Course { set; get; } }
在SchoolContext.cs中加入定义
public DbSet<StudentCoursePlan> StudentCoursePlan { get; set; }
增加在列出学生列表时选择指定学生,可为其增加自己选择选修课程,并计算已获取多少学分功能
在Student目录下的Index.cshtml文件添加一个按钮,按下后可以弹出一个可选定的课程列表
<td> <a asp-action="Edit" asp-route-id="@item.ID">Edit</a> | <a asp-action="Details" asp-route-id="@item.ID">Details</a> | <a asp-action="Delete" asp-route-id="@item.ID">Delete</a> | <a asp-action="Plan" asp-route-id="@item.ID">Plan</a> </td>
在Students.cs中增加对StudentCoursePlan的关联
public ICollection<StudentCoursePlan> StudentCoursePlan { get; set; }
在StudentsController.cs中增加Plan的Get动作
public async Task<IActionResult> Plan(int? id) { if (id == null) { return NotFound(); } var student = await _context.Students .Include(s => s.StudentCoursePlan) .ThenInclude(e => e.Course) .Include(e => e.Enrollments) .ThenInclude(e => e.Course) .AsNoTracking() .SingleOrDefaultAsync(m => m.ID == id); if (student == null) { return NotFound(); } PopulatePlanedCourse(student); return View(student); }
private void PopulatePlanedCourse(Student student) { List<StudentCoursePlanShowData> StudentCourseShow = new List<StudentCoursePlanShowData>(); var selectedCourse = student.StudentCoursePlan.Select(s => s.Course); var grade = ""; int? takedCredits = null; int? sumCredits = null; foreach (var course in selectedCourse) { if (course.Enrollments != null) { grade = student.Enrollments.Where(i => i.CourseID == course.CourseID).SingleOrDefault().Grade.ToString(); takedCredits = course.Credits / 5 * (5 - (int)student.Enrollments.Where(i => i.CourseID == course.CourseID).SingleOrDefault().Grade); sumCredits = (sumCredits ?? 0) + takedCredits; } else { grade = ""; takedCredits = null; } StudentCourseShow.Add(new StudentCoursePlanShowData { CourseID = course.CourseID, Title = course.Title, Grade = grade, TakedCredits = takedCredits }); } ViewData["StudentCourseShow"] = StudentCourseShow; ViewData["showNoData"] = StudentCourseShow.Count > 0 ? "hide" : "alert alert-warning"; ViewData["sumCredits"] = sumCredits; ViewData["studentID"] = student.ID; ViewData["UnselectedCourse"] = new List<StudentCoursePlanShowData>(); }
为了显示已选定的课程列表,在Models->SchoolViewModels目录下建立StudentCoursePlanShowData.cs
public class StudentCoursePlanShowData { public int CourseID { get; set; } public string Title { get; set; } public string Grade { get; set; } public int? TakedCredits { get; set; } }
Plan.cshtml
@model ContosoUniversity.Models.Student @using ContosoUniversity.Models.SchoolViewModels; @{ ViewData["Title"] = "Student Course Plan"; } <h2>The course that you ordered ... </h2> <div> <h4>Student</h4> <hr /> <p>Full Name : @Html.DisplayFor(model => model.FullName)</p> <span class="badge badge-info">Course List</span> <div class="@ViewData["showNoData"]">--没有数据--</div> <input type="hidden" [email protected](model => model.ID)> <table class="table table-bordered"> @if (((List<StudentCoursePlanShowData>)ViewData["StudentCourseShow"]).Count > 0) { <thead class="thead-inverse"> <tr> <th>CourseID</th> <th>Title</th> <th>Grade</th> <th>TakedCredits</th> </tr> </thead> } @foreach (var item in (List<StudentCoursePlanShowData>)ViewData["StudentCourseShow"]) { <tr> <td> @Html.DisplayFor(ModeItem => item.CourseID) </td> <td> @Html.DisplayFor(ModelItem => item.Title) </td> <td> @Html.DisplayFor(ModelItem => item.Grade) <div> </div> </td> <td> @Html.DisplayFor(ModelItem => item.TakedCredits) </td> </tr> } </table> @if (((List<StudentCoursePlanShowData>)ViewData["StudentCourseShow"]).Count > 0) { <div class="alert alert-success" role="alert"> <strong>Total TookCredts:</strong>@ViewData["sumCredits"] </div> } <div class="nav-divider"> <input class="btn btn-primary" type="button" id="btnPost" value="Post Test" data-toggle="modal" data-target="#modalSelectCourse" /> <a style="margin-left:20px" asp-action="Index">Back to List</a> @Html.AntiForgeryToken() @section Scripts{ @{ await Html.RenderPartialAsync("_ValidationScriptsPartial");} <script type="text/javascript" language="JavaScript"> $(document).ready(function () { $("#btnPost").on('click', function () { $("#dvShowData").load('@Url.Action("GetUnselectedCourse", "Students", new { id = Model.ID })'); }); }); </script> } </div> <!-- Modal --> <div class="modal" id="modalSelectCourse" tabindex="-1" role="dialog" aria-labelledby="modalLabel" aria-hidden="true"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title" id="modalLabel">Course List</h5> <button type="button" class="close" data-dismiss="modal" aria-label="Close"> <span aria-hidden="true">×</span> </button> </div> <form asp-action="Plan"> <div class="modal-body"> <div id="dvShowData"> @{ await Html.PartialAsync("resultsUnselectedCourse", Model); } </div> </div> <div class="modal-footer"> <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button> <button type="submit" class="btn btn-primary">Save changes</button> </div> </form> </div> </div> </div> </div>
加粗部分的js语句调用了GetUnselectedCourse方法生成未经选定的课程列表,按下Post Test按钮时弹出部分视图resultsUnselectedCourse.cshtml来显示,部分视图代码如下:
@model ContosoUniversity.Models.Student; @using ContosoUniversity.Models.SchoolViewModels; <h2>FullName:@Model.FullName</h2> <table class="table"> <thead> <tr> <th>CourseID</th> <th>Title</th> <th>Credits</th> <th>Select</th> </tr> </thead> <tbody> @foreach (var course in ((List<StudentCoursePlanShowData>)ViewData["UnselectedCourse"])) { <tr> <td>@course.CourseID</td> <td>@course.Title</td> <td>@course.TakedCredits</td> <td> <input class="checkbox" type="checkbox" name="stringSelectedCourse" value="@course.CourseID" /> </td> </tr> } </tbody> </table>
列出未经选定课程的方法
public async Task<IActionResult> GetUnselectedCourse(int? id) { var allCourses = _context.Courses; var viewModel = new List<StudentCoursePlanShowData>(); var student = await _context.Students.Include(s => s.StudentCoursePlan).AsNoTracking().SingleOrDefaultAsync(m => m.ID == id); if (student != null) { var studentSelectedCourse = new HashSet<int>(student.StudentCoursePlan.Select(c => c.CourseId)); foreach (var course in allCourses) { if (!studentSelectedCourse.Contains(course.CourseID)) viewModel.Add(new StudentCoursePlanShowData { CourseID = course.CourseID, Title = course.Title, TakedCredits = course.Credits }); } } ViewData["UnselectedCourse"] = viewModel; return PartialView("resultsUnselectedCourse", student); }
选定了课程按下 Save Change 按钮时 激发 Plan 的Post 方法,记录到StudentCoursePlan表
[HttpPost] [ValidateAntiForgeryToken] public async Task<IActionResult> Plan(int? id, string[] stringSelectedCourse) { if (id == null) { return NotFound(); } if (ModelState.IsValid) { UpdatePlanCourse(stringSelectedCourse, id ?? 0); try { await _context.SaveChangesAsync(); return RedirectToAction(nameof(Plan)); } catch (DbUpdateException) { ModelState.AddModelError("", "更新资料失败"); } } var student = await _context.Students .Include(s => s.StudentCoursePlan) .ThenInclude(e => e.Course) .Include(e => e.Enrollments) .ThenInclude(e => e.Course) .AsNoTracking() .SingleOrDefaultAsync(m => m.ID == id); PopulatePlanedCourse(student); return View(student); } private void UpdatePlanCourse(string[] stringSelectedCourse, int studentID) { int j; foreach (var course in stringSelectedCourse) { if (!int.TryParse(course, out j)) j = 0; _context.Add(new StudentCoursePlan { CourseId = j, StudentId = studentID }); } }
嗯,到这里就完成了,下一步看怎么完善一下它吧!