PnP*_*PnP 33 asp.net-mvc many-to-many entity-framework razor asp.net-mvc-3
我有一些与多对多关系的问题,保存了创建视图的结果.
我想为新的用户配置文件创建一个创建页面,该配置文件有一个清单,可以让他们选择课程(多对多关系).我的视图从Courses
数据库中获取记录,并使用复选框显示所有记录.
一旦用户发布数据,我想更新我的userprofile
模型,以及courses
多对多关系.那是我遗漏的代码!
我是MVC的新手,我一直在研究,但我还没有做到.
我遵循这个例子:http: //www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/updating-related-data-with-the-entity-framework-in-an- ASP净MVC应用程序
这是模型:
public class UserProfile
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Courses> usercourses { get; set; }
}
public class Courses
{
public int CourseID { get; set; }
public string CourseDescripcion { get; set; }
public virtual ICollection<UserProfile> UserProfiles { get; set; }
}
public class UserProfileDBContext : DbContext
{
public DbSet<UserProfile> UserProfiles { get; set; }
public DbSet<Courses> usrCourses{ get; set; }
}
Run Code Online (Sandbox Code Playgroud)
我还添加了一个ViewModel:
namespace Mysolution.ViewModels
{
public class AssignedCourseData
{
public int CourseID { get; set; }
public string CourseDescription { get; set; }
public bool Assigned { get; set; }
}
}
Run Code Online (Sandbox Code Playgroud)
这是create
填充课程复选框的Controller:
public ActionResult Create()
{
PopulateCoursesData();
return View();
}
private void PopulateCoursesData()
{
var CoursesData = db.usrCourses;
var viewModel = new List<AssignedCourseData>();
foreach (var item in CoursesData)
{
viewModel.Add(new AssignedCourseData {
CourseID = item.CourseID,
CourseDescription = item.CourseDescription,
Assigned = false });
}
ViewBag.CoursePopulate = viewModel;
}
Run Code Online (Sandbox Code Playgroud)
这是观点
@{
int cnt = 0;
List<MySolution.ViewModels.AssignedCourseData> courses = ViewBag.CoursePopulate;
foreach (var course in courses)
{
<input type="checkbox" name="selectedCourse" value="@course.CourseID" />
@course.CourseDescription
}
}
Run Code Online (Sandbox Code Playgroud)
这是获取数据的控制器(以及我想要保存的位置).它作为string[] selectedCourse
复选框的参数:
[HttpPost]
public ActionResult Create(UserProfile userprofile, string[] selectedCourse)
{
if (ModelState.IsValid)
{
db.UserProfiles.Add(userprofile);
//TO DO: Save data from many to many (this is what I can't do!)
db.SaveChanges();
}
return View(userprofile);
}
Run Code Online (Sandbox Code Playgroud)
Cia*_*uen 73
编辑:我在3篇博客文章中写了这个代码
Github来源:https: //github.com/cbruen1/mvc4-many-to-many
我认为你在某些命名方面偏离了惯例,所以我在我认为合适的地方做了改变.在我看来,将课程作为UserProfile的一部分发回的最佳方式是通过编辑器模板呈现它们,我将进一步解释.
以下是我将如何实现这一切:
(感谢@Slauma在保存新课程时指出了一个错误).
从DB开始,按原样保留UserProfile集合,并命名课程集合课程:
public DbSet<UserProfile> UserProfiles { get; set; }
public DbSet<Course> Courses { get; set; }
Run Code Online (Sandbox Code Playgroud)
在DbContext类中重写OnModelCreating方法.这就是你如何映射UserProfile和Course之间的多对多关系:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<UserProfile>()
.HasMany(up => up.Courses)
.WithMany(course => course.UserProfiles)
.Map(mc =>
{
mc.ToTable("T_UserProfile_Course");
mc.MapLeftKey("UserProfileID");
mc.MapRightKey("CourseID");
}
);
base.OnModelCreating(modelBuilder);
}
Run Code Online (Sandbox Code Playgroud)
我还会在同一个命名空间中添加一个模拟初始化程序类,它将为您提供一些入门课程,这意味着您不必在每次模型更改时手动添加它们:
public class MockInitializer : DropCreateDatabaseAlways<MVC4PartialViewsContext>
{
protected override void Seed(MVC4PartialViewsContext context)
{
base.Seed(context);
var course1 = new Course { CourseID = 1, CourseDescripcion = "Bird Watching" };
var course2 = new Course { CourseID = 2, CourseDescripcion = "Basket weaving for beginners" };
var course3 = new Course { CourseID = 3, CourseDescripcion = "Photography 101" };
context.Courses.Add(course1);
context.Courses.Add(course2);
context.Courses.Add(course3);
}
}
Run Code Online (Sandbox Code Playgroud)
将此行添加到Application_Start()Global.asax以启动它:
Database.SetInitializer(new MockInitializer());
Run Code Online (Sandbox Code Playgroud)
所以这是模型:
public class UserProfile
{
public UserProfile()
{
Courses = new List<Course>();
}
public int UserProfileID { get; set; }
public string Name { get; set; }
public virtual ICollection<Course> Courses { get; set; }
}
public class Course
{
public int CourseID { get; set; }
public string CourseDescripcion { get; set; }
public virtual ICollection<UserProfile> UserProfiles { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
现在,在Controller中创建2个新的操作结果,以创建新的用户配置文件:
public ActionResult CreateUserProfile()
{
var userProfileViewModel = new UserProfileViewModel { Courses = PopulateCourseData() };
return View(userProfileViewModel);
}
[HttpPost]
public ActionResult CreateUserProfile(UserProfileViewModel userProfileViewModel)
{
if (ModelState.IsValid)
{
var userProfile = new UserProfile { Name = userProfileViewModel.Name };
AddOrUpdateCourses(userProfile, userProfileViewModel.Courses);
db.UserProfiles.Add(userProfile);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(userProfileViewModel);
}
Run Code Online (Sandbox Code Playgroud)
这是你的PopulateCourseData类似于你的方式,除了不要放入ViewBag - 它现在是UserProfileViewModel上的一个属性:
private ICollection<AssignedCourseData> PopulateCourseData()
{
var courses = db.Courses;
var assignedCourses = new List<AssignedCourseData>();
foreach (var item in courses)
{
assignedCourses.Add(new AssignedCourseData
{
CourseID = item.CourseID,
CourseDescription = item.CourseDescripcion,
Assigned = false
});
}
return assignedCourses;
}
Run Code Online (Sandbox Code Playgroud)
创建编辑器模板 - 在Views\Shared文件夹中创建一个名为EditorTemplates的新文件夹(如果您还没有).添加一个名为AssignedCourseData的新局部视图并粘贴下面的代码.这有点神奇,可以正确呈现和命名所有复选框 - 您不需要每个循环,因为编辑器模板将创建集合中传递的所有项目:
@model AssignedCourseData
@using MySolution.ViewModels
<fieldset>
@Html.HiddenFor(model => model.CourseID)
@Html.CheckBoxFor(model => model.Assigned)
@Html.DisplayFor(model => model.CourseDescription)
</fieldset>
Run Code Online (Sandbox Code Playgroud)
在视图模型文件夹中创建用户配置文件视图模型 - 它具有AssignedCourseData对象的集合:
public class UserProfileViewModel
{
public int UserProfileID { get; set; }
public string Name { get; set; }
public virtual ICollection<AssignedCourseData> Courses { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
添加一个名为CreateUserprofile.cshtml的新视图来创建用户配置文件 - 您可以右键单击已添加的CreateUserProfile控制器方法并选择"添加视图":
@model UserProfileViewModel
@using MySolution.ViewModels
@using (Html.BeginForm("CreateUserProfile", "Course", FormMethod.Post))
{
@Html.ValidationSummary(true)
<fieldset>
@Html.DisplayFor(model => model.Name)
@Html.EditorFor(model => model.Name)
// Render the check boxes using the Editor Template
@Html.EditorFor(x => x.Courses)
</fieldset>
<p>
<input type="submit" value="Create" />
</p>
}
Run Code Online (Sandbox Code Playgroud)
这将正确呈现字段名称,以便在将表单发布回Controller时它们是用户配置文件视图模型的一部分.这些字段将如下命名:
<fieldset>
<input data-val="true" data-val-number="The field CourseID must be a number." data-val-required="The CourseID field is required." id="Courses_0__CourseID" name="Courses[0].CourseID" type="hidden" value="1" />
<input data-val="true" data-val-required="The Assigned field is required." id="Courses_0__Assigned" name="Courses[0].Assigned" type="checkbox" value="true" /><input name="Courses[0].Assigned" type="hidden" value="false" />
Bird Watching
</fieldset>
Run Code Online (Sandbox Code Playgroud)
其他字段将以相似的名称命名,除了分别用1和2索引.最后,这里是如何在回发表单时将课程保存到新用户配置文件.将此方法添加到Controller中 - 在回发表单时从CreateUserProfile操作结果中调用此方法:
private void AddOrUpdateCourses(UserProfile userProfile, IEnumerable<AssignedCourseData> assignedCourses)
{
foreach (var assignedCourse in assignedCourses)
{
if (assignedCourse.Assigned)
{
var course = new Course { CourseID = assignedCourse.CourseID };
db.Courses.Attach(course);
userProfile.Courses.Add(course);
}
}
}
Run Code Online (Sandbox Code Playgroud)
一旦课程成为用户档案的一部分,EF负责协会.它将为在OnModelCreating中创建的T_UserProfile_Course表中选择的每个课程添加一条记录.这是CreateUserProfile操作结果方法,显示了发回的课程:
我选择了2门课程,您可以看到课程已添加到新用户配置文件对象中:
归档时间: |
|
查看次数: |
42632 次 |
最近记录: |