在编辑文章更新的关系与MVC控制器模型绑定 [英] Update relationships on edit POST with model bind from MVC controller

查看:112
本文介绍了在编辑文章更新的关系与MVC控制器模型绑定的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用实体框架与许多一对多的关系,我很困惑如何更新从ASP.NET MVC控制器所在的模式势必这种关系。

Using Entity Framework with a many-to-many relationship, I'm confused how to update that relationship from an ASP.NET MVC controller where the model is bound.

例如,一个博客:那里的帖子有很多标签和标签有很多帖子

For example, a blog: where posts have many tags, and tags have many posts.

Posts控制器的编辑操作失败延迟加载标记实体:

Posts controller edit action fails to lazy load tags entities:

public class PostsController : Controller
{
    [Route("posts/edit/{id}")]
    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<ActionResult> Edit([Bind(Include = "Id,Title,Tags")] Post post)
    {
        // Post tags is null
        Post.tags.ToList();
    }
}

上面,HTTP POST绑定属性模型;但是, Post.tags 关系为null。

有没有办法让我去查询, .INCLUDE(P =&GT; p.Tags)附加()后使用检索相关标签实体此 [装订()]

There's no way for me to query, .Include(p => p.Tags), or Attach() the post to retrieve the related tag entities using this [Bind()].

在视图方面,我使用的一个标记,并通过FORMDATA - 我不使用MVC列表组件。所以,问题是没有约束力的观点FORMDATA - 问题是, .tags添加属性不是延迟加载实体

On the view side, I'm using a tokenizer and passing formdata - I'm not using a MVC list component. So, the issue is not binding the view formdata - the issue is that the .tags property is not lazy loading the entities.

这关系是功能性 - 从剃刀CSHTML认为我能够遍历集合,并查看孩子的标签。

This relationship is functional - from the Razor cshtml view I am able to traverse the collection and view children tags.

从浏览后,我可以查看标签(这工作)

From the Post View, I can view tags (this works)

@foreach (var tag in Model.Tags) {
}

从标签视图,我可以查看的帖子(这工作)

From the Tag View, I can view posts (this works)

@foreach (var post in Model.Posts) {
}

同样在创建从帖子控制器动作,我可以创建新的标签实体和持续的关系。

Likewise on create action from the Posts controller, I can create new tag entities and persist their relationship.

public class PostsController : Controller
{
    [Route("posts/create")]
    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<ActionResult> Create([Bind(Include = "Title,Content")] Post post)
    {
        string[] tagNames = this.Request.Form["TagNames"].Split(',').Select(tag => tag.Trim()).ToArray();

        post.Tags = new HashSet<Tag>();

        Tag tag = new Tag();
        post.Tags.Add(tag);

        if (ModelState.IsValid)
        {
            db.posts.Add(post);
            await db.SaveChangesAsync();
            return RedirectToAction("Admin");
        }

        return View(post);
    }

这些关系在任何地方工作,除了此编辑HTTP POST。作为参考,它们的定义如下:

These relationships work everywhere except for this edit HTTP Post. For reference, they are defined as:

public class Post
{
    public virtual ICollection<Tag> Tags { get; set; }
}

public class Tag
{
    public virtual ICollection<Post> Posts { get; set; }
}

只有在编辑行动HTTP POST我不能访问职位标签。

Only on HTTP Post of edit action can I not access tags of posts.

我如何可以加载相关的标签,以改变该集合?

How can I load related tags to alter that collection?

推荐答案

您的问题无关,与实体框架。它基本上是一个问题,当你发布一个模型/视图模型与表单集合属性,集合属性将变为空。

Your problem has nothing to do with Entity framework. It is basically an issue when you post a model/viewmodel with a collection property from your form, the collection property becomes null.

您可以通过使用EditorTemplates解决这个问题。

You can solve this by using EditorTemplates.

看起来你正在使用由您的看法实体框架生成的实体类。一般来说,这不是一个好主意,因为现在你的UI层是紧耦合的EF实体。如果明天你想你的数据访问code形式实行EF改为以任何理由别的什么?

It looks like you are using the entity classes generated by Entity framework in your views. Generally this is not a good idea because now your UI layer is tightly coupled to EF entities. What if tomorrow you want to change your data access code implemenation form EF to something else for any reasons ?

让我们创造一些的ViewModels在UI层使用。的ViewModels是简单的POCO类。该的ViewModels将有哪些看法绝对需要的属性。不只是复制所有实体类的属性并粘贴到你的ViewModels。

So Let's create some viewmodels to be used in the UI layer. Viewmodels are simple POCO classes. The viewmodels will have properties which the view absolutely need. Do not just copy all your entity class properties and paste in your viewmodels.

public class PostViewModel
{
    public int Id { set; get; }
    public string Title { set; get; }
    public List<PostTagViewModel> Tags { set; get; }
}

public class PostTagViewModel
{
    public int Id { set; get; }
    public string TagName { set; get; }
    public bool IsSelected { set; get; }
}

现在在你付诸行动,您将创建PostViewModel类的对象,初始化标签收集和发送到视图。

Now in your GET action, you will create an object of your PostViewModel class, Initialize the Tags collection and send to the view.

public ActionResult Create()
{
    var v =new PostViewModel();
    v.Tags = GetTags();
    return View(v);
}
private List<PostTagViewModel> GetTags()
{
    var db = new YourDbContext();
    return db.Tags.Select(x=> new PostTagViewModel { Id=x.Id, TagName=x.Name})
         .ToList();

} 

现在,让我们创建一个编辑模板。转至〜/查看/ YourControllerName 目录,并创建一个名为子目录的 EditorTemplates 。名为 PostTagViewModel.cshtml 创建一个新的视图那里。

Now, Let's create an editor template. Go to the ~/Views/YourControllerName directory and create a sub directory called EditorTemplates. Create a new view there with the name PostTagViewModel.cshtml.

添加下面的code到新的文件。

Add the below code to the new file.

@model YourNamespaceHere.PostTagViewModel
<div>
    @Model.TagName
    @Html.CheckBoxFor(s=>s.IsSelected)
    @Html.HiddenFor(s=>s.Id)      
</div>

在这里输入的形象描述

现在,在其中强制类型来PostViewModel我们的主要观点(create.cshtml),我们将调用 Html.EditorFor helper方法使用的编辑器模板。

Now, in our main view (create.cshtml) which is strongly typed to PostViewModel, we will call Html.EditorFor helper method to use the editor template.

@model YourNamespaceHere.PostViewModel
@using (Html.BeginForm())
{
    <label>Post title</label>
    @Html.TextBoxFor(s=>s.Title)

    <h3>Select tags</h3>
    @Html.EditorFor(s=>s.Tags)

    <input type="submit"/>
}

现在在你的HttpPost操作方法,可以检查是否有标签收集发布模式。

Now in your HttpPost action method, you can inspect the posted model for Tags collection.

[HttpPost]
public ActionResult Create(PostViewModel model)
{
    if (ModelState.IsValid)
    {
       // Put a break point here and inspect model.
        foreach (var tag in model.Tags)
        {
            if (tag.IsSelected)
            {
                // Tag was checked from UI.Save it
            }
        }
        // to do : Save Post,Tags and then redirect.
    }
    model.Tags = GetTags(); //reload tags again 
    return View(model);
}

所以,因为我们HttpPost操作的参数是PostViewModel的对象,我们需要节约使用实体框架,它把它映射到实体类。

So since our HttpPost action's parameter is an object of PostViewModel, we need to map it to your Entity classes to save it using entity framework.

var post= new Post { Title = model.Title };
foreach(var t in model.Tags)
{
   if(t.IsSelected)
   {
      var t = dbContext.Tags.FirstOrDefault(s=>s.Id==t.Id);
      if(t!=null)
      { 
        post.Tags.Add(t);
      }
   }
}
dbContext.Posts.Add(post);
await dbContext.SaveChangesAsync();

这篇关于在编辑文章更新的关系与MVC控制器模型绑定的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆