Asp.net mvc 在MVC创建视图上保存多对多关系数据

Asp.net mvc 在MVC创建视图上保存多对多关系数据,asp.net-mvc,asp.net-mvc-3,entity-framework,razor,many-to-many,Asp.net Mvc,Asp.net Mvc 3,Entity Framework,Razor,Many To Many,我在保存create视图的结果时遇到了一些多对多关系问题 我想为一个新的用户配置文件创建一个页面,该页面有一个清单,允许他们选择课程(多对多关系)。 我的视图从课程数据库中获取记录,并用复选框显示所有记录 一旦用户发布数据,我想更新我的userprofile模型,以及课程多对多关系。这就是我丢失的代码 我是MVC的新手,我一直在研究,但我还不能做到 我举这个例子: 这就是模型: public class UserProfile { public int Id { get; set; }

我在保存create视图的结果时遇到了一些多对多关系问题

我想为一个新的用户配置文件创建一个页面,该页面有一个清单,允许他们选择课程(多对多关系)。 我的视图从
课程
数据库中获取记录,并用复选框显示所有记录

一旦用户发布数据,我想更新我的
userprofile
模型,以及
课程
多对多关系。这就是我丢失的代码

我是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; }
}
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; }
}
这是填充课程复选框的
创建
控制器:

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;
}
[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);
}

编辑:我在3篇博客文章中用代码写了这篇文章

  • 设置解决方案并创建新用户
  • 添加课程并将其与用户配置文件一起保存
  • 允许编辑和删除用户及其课程
Github来源:


例如,我认为你在一些命名方面有点偏离了惯例,所以我在我认为合适的地方做了一些更改。在我看来,将课程作为UserProfile的一部分发回的最佳方法是使用编辑器模板呈现它们,我将对此进行进一步解释

以下是我将如何实现所有这些:

(感谢@Slauma在保存新课程时指出了一个错误)

  • 在您的模型中,您的“课程”类是一个单独的实体,通常被命名为课程,而课程的集合将被命名为课程
  • 使用视图模型,而不是在ViewBag中指定CourseData
  • 在创建新用户时执行此操作-即,为包含AssignedCourseData视图模型的Userprofile创建标准视图,该视图模型将与UserProfileViewModel一起发布
从DB开始,保持UserProfile集合不变,并将课程集合命名为课程:

public DbSet<UserProfile> UserProfiles { get; set; }
public DbSet<Course> Courses { get; set; }
这就是模型:

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; }
}
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; }
}
这是您的PopulateCourseData,与您使用它的方式类似,只是不放在ViewBag中-它现在是UserProfileViewModel上的一个属性:

namespace Mysolution.ViewModels
{
    public class AssignedCourseData
    {
        public int CourseID { get; set; }
        public string CourseDescription { get; set; }
        public bool Assigned { get; set; }
    }
}
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;
}
private ICollection PopulateCourseData()
{
var课程=db.课程;
var assignedCourses=新列表();
foreach(课程中的var项目)
{
assignedCourses.Add(新AssignedCourseData
{
CourseID=item.CourseID,
CoursedDescription=item.CoursedDescription,
赋值=假
});
}
返回指定课程;
}
创建编辑器模板-在视图\共享文件夹中创建一个名为EditorTemplates的新文件夹(如果您还没有)。添加名为AssignedCourseData的新局部视图,并粘贴下面的代码。这是正确呈现和命名所有复选框的神奇之处-您不需要为每个循环指定一个值,因为编辑器模板将创建在集合中传递的所有项:

@model AssignedCourseData
@using MySolution.ViewModels

<fieldset>
    @Html.HiddenFor(model => model.CourseID)    
    @Html.CheckBoxFor(model => model.Assigned)
    @Html.DisplayFor(model => model.CourseDescription)
</fieldset>
@model AssignedCourseData
@使用MySolution.ViewModels
@Html.HiddenFor(model=>model.CourseID)
@CheckBoxFor(model=>model.Assigned)
@DisplayFor(model=>model.CourseDescription)
在“视图模型”文件夹中创建用户纵断面图模型-其中包含一组AssignedCourseData对象:

public class UserProfileViewModel
{
    public int UserProfileID { get; set; }
    public string Name { get; set; }
    public virtual ICollection<AssignedCourseData> Courses { get; set; }
}
公共类UserProfileViewModel
{
public int UserProfileID{get;set;}
公共字符串名称{get;set;}
公共虚拟ICollection课程{get;set;}
}
添加名为CreateUserprofile.cshtml的新视图以创建用户配置文件-您可以右键单击已添加的CreateUserprofile控制器方法并选择“添加视图”:

@model UserProfileViewModel
@使用MySolution.ViewModels
@使用(Html.BeginForm(“CreateUserProfile”、“Course”、FormMethod.Post))
{
@Html.ValidationSummary(true)
@DisplayFor(model=>model.Name)
@EditorFor(model=>model.Name)
//使用编辑器模板呈现复选框
@EditorFor(x=>x.Courses)

}
这将正确呈现字段名称,以便在表单发回控制器时,它们是用户纵断面图模型的一部分。这些字段将被命名为:

<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>

观鸟
除分别用1和2编制索引外,其他字段将以类似方式命名。最后,这里介绍了在表单发回时如何将课程保存到新的用户配置文件中。将此方法添加到控制器-当表单发回时,从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); 
        }
    }
}
private void addor updatecourses(UserProfile UserProfile,IEnumerable assignedCourses)
{
foreach(分配课程中的var分配课程)
{
if(已分配课程。已分配)
{
var课程=新课程{CourseID=assignedCourse.CourseID};
db.课程。附件(课程);
userProfile.Courses.Add(课程);
}
}
}
一旦课程成为用户配置文件的一部分,EF将负责关联。它将为在OnModelCreating中创建的T_UserProfile_课程表中选择的每门课程添加一条记录。以下是CreateUserProfile操作结果方法,其中显示了回发的课程:

我选择了2门课程,您可以看到这些课程已添加到新的用户配置文件对象中:


+1非常详细的答案!唯一缺少的是将课程附加到上下文,否则EF将在数据库中创建重复的课程。在
AddOrUpdateCourses
var课程=新课程{…};db.课程。附件(课程);userProfile.Courses.Add(课程)你是对的,很有看点。后来我注意到数据库中有一些错误的课程,但没有时间去查。这个答案太棒了!。。。雷亚尔
public class UserProfileViewModel
{
    public int UserProfileID { get; set; }
    public string Name { get; set; }
    public virtual ICollection<AssignedCourseData> Courses { get; set; }
}
@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>    
}
<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>
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); 
        }
    }
}