有一篇关于how to update related data with the Entity Framework in an ASP.NET MVC application的文章。它实现了一个简单的大学,您可以选择您的课程作为教师。
以下是其课程控制器的简化版本:
private void UpdateInstructorCourses(string[] selectedCourses, Instructor instructorToUpdate)
{
if (selectedCourses == null)
{
instructorToUpdate.Courses = new List<Course>();
return;
}
var selectedCoursesHS = new HashSet<string>(selectedCourses);
var instructorCourses = new HashSet<int>
(instructorToUpdate.Courses.Select(c => c.CourseID));
foreach (var course in db.Courses)
{
if (selectedCoursesHS.Contains(course.CourseID.ToString()))
{
if (!instructorCourses.Contains(course.CourseID))
{
instructorToUpdate.Courses.Add(course);
}
}
else
{
if (instructorCourses.Contains(course.CourseID))
{
instructorToUpdate.Courses.Remove(course);
}
}
}
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(int? id, string[] selectedCourses)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var instructorToUpdate = db.Instructors
.Include(i => i.Courses)
.Where(i => i.ID == id)
.Single();
if (TryUpdateModel(instructorToUpdate, "",
new string[] { "LastName", "FirstMidName", "HireDate", "OfficeAssignment" }))
{
try
{
UpdateInstructorCourses(selectedCourses, instructorToUpdate);
db.SaveChanges();
return RedirectToAction("Index");
}
catch (Exception e)
{
//Log the error
}
}
PopulateAssignedCourseData(instructorToUpdate);
return View(instructorToUpdate);
}
正如您所看到的,UpdateInstructorCourses
根据instructorToUpdate.Courses
基于字符串数组从db.Courses
检索的对象填充selectedCourses
。
那么,这是创建多对多关系的唯一方法吗?我们是否需要从db
然后Add
将对象添加到我们的List成员中?仅传递相关对象的ID并更新相关数据不是更好吗?
答案 0 :(得分:0)
因此,对于多对多映射,在EF中有两种方法:
1)两个ICollection
属性(您已经在使用):
public class Instructor
{
public Int32 Id { get; set; }
public ICollection<Course> Courses { get; set; }
}
public class Course
{
public Int32 Id { get; set; }
public ICollection<Instructor> Instructors { get; set; }
}
在这种情况下,EF将生成/使用映射表,例如:
CREATE TABLE [dbo].[Instructors]([Id])
CREATE TABLE [dbo].[Courses]([Id])
CREATE TABLE [dbp].[Instructor_Courses_Mapping]([Id],[InstructorId],[CoursesId])
现在,正如您所指出的那样,无法从该映射表中获取列表,使您可以使用导航属性将集合加载到内存中。所以:
2)但是,您可以使用自己的自定义映射实体覆盖EF的映射表生成:
public class Instructor
{
public Int32 Id { get; set; }
public ICollection<InstructorCourse> InstructorCourses { get; set; }
}
public class Course
{
public Int32 Id { get; set; }
public ICollection<InstructorCourse> InstructorCourses { get; set; }
}
public class InstructorCourse
{
public Int32 Id { get; set; }
public Int32 InstructorId { get; set; }
public Instructor Instructor { get; set; }
public Int32 CourseId { get; set; }
public Course Course { get; set; }
}
现在,EF将生成这些表:
CREATE TABLE [dbo].[Instructors]([Id])
CREATE TABLE [dbo].[Courses]([Id])
CREATE TABLE [dbp].[InstructorCourses]([Id],[InstructorId],[CourseId])
这将允许您使用dbContext查询InstructorCourses
:
var instructorCourses = dbContext.Set<InstructorCourse>().Where( c => c.InstructorId == instructorId ).ToList()
这将返回InstructorCourse
个对象的列表,其中所有InstructorId
值与您要查找的值匹配。然后,如果您想添加/删除映射:
//add item
dbContext.Set<InstructorCourse>().Add(new InstructorCourse()
{
InstructorId = instructorId,
CourseId = courseId
});
dbContext.SaveChanges();
//remove item
var itemToRemove = dbContext.Set<InstructorCourse>().FirstOrDefault( c => c.InstructorId == instructorId && c.CourseId == courseId);
dbContext.Set<InstructorCourse>().Remove(itemToRemove);
dbContext.SaveChanges();
我发现这个方法更清晰,表示你的数据库结构更清晰,但它确实使嵌套的Linq语句更复杂,并且nulls(没有适当的外键限制)可能更常见。