保存多对多的关系数据的MVC创建视图(Saving Many to Many relationshi

2019-06-17 11:38发布

我有一个多一对多的关系保存创建视图的结果的一些问题。

我想为有一个清单,让他们选择课程(多对多的关系)的新用户配置文件做一个创建页面。 我认为需要从记录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; }
}

我还添加了一个视图模型:

namespace Mysolution.ViewModels
{
    public class AssignedCourseData
    {
        public int CourseID { get; set; }
        public string CourseDescription { get; set; }
        public bool Assigned { get; set; }
    }
}

这是create控制器,填充课程复选框:

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

这是视图

@{
    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
    }
}

这是获取数据(和我想要保存它)的CONTROLER。 它得到的参数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);
}

Answer 1:

编辑 :我在3篇博客文章,代码写这件事

  • 部分1设置的溶液,并创建一个新的用户
  • 第2部分增加了课程,并与用户配置文件并将其保存
  • 第3部分允许用户和他们的课程的编辑和删除

Github上源: https://github.com/cbruen1/mvc4-many-to-many


我想你已经从约定在你的一些命名,例如有一点点,所以我所做的改动,我认为合适的偏离。 在我看来,最好的方法有课程调回为用户配置的一部分,是让他们通过编辑模板,我进一步解释上呈现。

这是我将如何实现这一切:

(感谢@Slauma保存新的课程时,指出了一个bug)。

  • 在模型中,您的“课程”类是单一的实体,通常会被命名为课程和精品课程的集合将被命名为课程。
  • 而不是在ViewBag具有AssignedCourseData使用视图模型
  • 实现这个在创建新用户 - 即有一个标准,含有将被调回与UserProfileViewModel的AssignedCourseData视图模型USERPROFILE创建视图。

从数据库开始离开用户配置集合作为是并命名课程集课程:

public DbSet<UserProfile> UserProfiles { get; set; }
public DbSet<Course> Courses { get; set; }

在的DbContext类重写OnModelCreating方法。 这是你如何在众多映射到用户配置和课程之间的多对多关系:

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

我也将在同一个命名空间,会给你一些课程入手,并意味着你不必在每次你的模型发生变化时手动添加它们添加一个模拟初始化类:

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

该行添加到的Application_Start()的Global.asax来启动它:

Database.SetInitializer(new MockInitializer());

因此,这里的模型:

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

现在创建您的控制器创建一个新的用户配置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);
}

这是你的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;
}

创建编辑模板 - 在你的浏览\共享文件夹创建一个新的文件夹,名为EditorTemplates,如果你不已经有一个。 添加一个名为AssignedCourseData一种新的局部视图和粘贴下面的代码。 这是神奇的呈现和正确名称的所有复选框位 - 你不需要每个循环的编辑模板将创建一个集合传递的所有项目:

@model AssignedCourseData
@using MySolution.ViewModels

<fieldset>
    @Html.HiddenFor(model => model.CourseID)    
    @Html.CheckBoxFor(model => model.Assigned)
    @Html.DisplayFor(model => model.CourseDescription)
</fieldset>

创建您的视图模型文件夹中的用户配置文件视图模型 - 这有AssignedCourseData对象的集合:

public class UserProfileViewModel
{
    public int UserProfileID { get; set; }
    public string Name { get; set; }
    public virtual ICollection<AssignedCourseData> Courses { get; set; }
}

添加一个名为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>    
}

这会使得字段名称正确,以使他们的用户配置文件的视图模型的一部分,当窗体回发到控制器。 该领域将被命名为这样的:

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

一旦课程是用户配置文件的一部分EF负责的联想。 这将添加一条记录选定在OnModelCreating创建T_UserProfile_Course表中的每个过程。 这里的回发显示课程CreateUserProfile行动结果的方法:

我选择了2个疗程,你可以看到,该课程已被添加到新的用户配置文件对象:



文章来源: Saving Many to Many relationship data on MVC Create view