ASP.NET MVC 5 - 脚手架为多对一的关系 [英] ASP.NET MVC 5 - Scaffolding for Many to One Relationship

查看:132
本文介绍了ASP.NET MVC 5 - 脚手架为多对一的关系的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我工作的ASP.NET MVC 5,6 EF,剃刀引擎,VB语言和数据库首先引桥VS 2013。

I am Working on ASP.NET MVC 5, EF 6, Razor Engine, VB Language and Database First Approach with VS 2013.

现在,在我的数据库;我有两个表如下:

Now, in my DB; I have two tables as below:

CREATE TABLE [dbo].[Group]
(
    [Id]    INT          NOT NULL PRIMARY KEY IDENTITY(1, 1), 
    [Name]  VARCHAR(50)  NOT NULL
)

CREATE TABLE [dbo].[Subscriber]
(
    [Id]          INT              NOT NULL  PRIMARY KEY IDENTITY(1, 1),
    [FirstName]   [nvarchar](100)  NOT NULL,
    [MiddleName]  [nvarchar](100)  NULL,
    [LastName]    [nvarchar](100)  NOT NULL, 
    [Email]       [varchar] (200)  NOT NULL  UNIQUE, 
    [GroupId]     INT              NULL      REFERENCES [Group] ON DELETE SET NULL
)

现在,当我使用自动生成的控制器和视图的脚手架;我收到了<选择>控制(与所有项目为<&选项GT;内部)。在创建用户和编辑用户的意见

Now, when I autogenerate the Controllers and Views using Scaffolding; I get a <select> control (with all Group items as <option> inside) in "Create Subscriber" and "Edit Subscriber" views.

但其实,我想要的创建组和编辑组的观点来问我在订阅我要的特定组中添加。对于相同的HTML控件可以是复选框的列表&LT;选择多个=多​​个&GT; 所有用户项目为&lt;&选项GT; S

But actually, I want the "Create Group" and "Edit Group" views to ask me the Subscribers I want to add in the particular group. The HTML control for the same can be a list of checkbox or <select multiple="multiple"> with all Subscriber items as <option>s.

我怎么能autgenerate /实施?

How can I autgenerate/implement that?

推荐答案

不要太依赖脚手架。整点是,它给你一个基地,从工作;它不是BE-全部终止全你的看法。您可以和应该修改脚手架,以满足您的需求,说实话,往往不是,它更容易只是从头开始,而不是试图取消所有不必要的绒毛脚手架补充说。

Don't rely too heavily on the scaffolding. The whole point is that it gives you a base to work from; it's not the be-all-end-all to your view. You can and should modify the scaffolding to suit your needs, and honestly, more often than not, it's easier just to start from scratch than to try to undo all the unnecessary fluff the scaffolding adds.

这是说,一次选择多个相关项目尤其是当你的需求的视图模型。尝试使用您的这个实体会虎头蛇尾快。因此,创建一个像类:

That said, especially when choosing multiple related items at once, you need a view model. Trying to use your entity for this is going to run out of steam fast. So create a class like:

public class GroupViewModel
{
    // `Group` properties you need to edit here

    public List<int> SelectedSubscriberIds { get; set; }

    public IEnumerable<SelectListItem> SubscriberChoices { get; set; }
}

然后,在你的控制器:

Then, in your controller:

// We'll use this code multiple times so it's factored out into it's own method
private void PopulateSubscriberChoices(GroupViewModel model)
{
    model.SubscriberChoices = db.Subscribers.Select(m => new SelectListItem
    {
        Value = m.Id.ToString(),
        Text = m.FirstName + " " + m.LastName
    });
}

public ActionResult Create()
{
    var model = new GroupViewModel();

    PopulateSubscriberChoices(model);
    return View(model);
}

[HttpPost]
public ActionResult Create(GroupViewModel model)
{
    if (ModelState.IsValid)
    {
        // Map the posted values onto a new `Group` instance. To set `Subscribers`,
        // lookup instances from the database using the list of ids the user chose
        var group = new Group
        {
            Name = model.Name,
            Subscribers = db.Subscribers.Where(m => model.SelectedSubscriberIds.Contains(m.Id))
        };
        db.Groups.Add(group);
        db.SaveChanges()

        return RedirectToAction("Index");
    }

    PopulateSubscriberChoices(model);
    return View(model);
}

public ActionResult Edit(int id)
{
    var group = db.Groups.Find(id);
    if (group == null)
    {
        return new HttpNotFoundResult();
    }

    // Map `Group` properties to your view model
    var model = new GroupViewModel
    {
        Name = group.Name,
        SelectedSubscriberIds = group.Subscribers.Select(m => m.Id).ToList()
    };

    PopulateSubscriberChoices(model);
    return View(model);
}

[HttpPost]
public ActionResult Edit(int id, GroupViewModel model)
{
    var group = db.Groups.Find(id);
    if (group == null)
    {
        return new HttpNotFoundResult();
    }

    if (ModelState.IsValid)
    {
        group.Name = model.Name;

        // Little bit trickier here
        // First remove subscribers that are no longer selected
        group.Subscribers.Where(m => !model.SelectedSubscriberIds.Contains(m.Id))
            .ToList().ForEach(m => group.Subscribers.Remove(m));

        // Now add newly selected subscribers
        var existingSubscriberIds = group.Subscribers.Select(m => m.Id);
        var newSubscriberIds = model.SelectedSubscriberIds.Except(existingSubscriberIds);
        db.Subscribers.Where(m => newSubscriberIds.Contains(m.Id))
            .ToList().ForEach(m => group.Subscribers.Add(m));

        db.Entry(group).State = EntityState.Modified;
        db.SaveChanges()

        return RedirectToAction("Index");
    }

    PopulateSubscriberChoices(model);
    return View(model);
}

编辑后的动作是最困难的。为了不得到关于重复键和这样的错误,你需要确保你没有重复的项目添加到集合。你还需要确保删除此组和用户为未选中任何项目之间的关系。除此之外,它的pretty直线前进。

The edit post action is the most difficult. In order to not get errors about duplicate keys and such, you need to make sure you don't add duplicate items to the collection. You also need to make sure to remove the relationship between this group and any items the user has unselected. Other than that, it's pretty straight forward.

最后,在你的看法,你只需要一个渲染选择列表:

Finally in your views, you just need a to render the select list:

@model Namespace.To.GroupViewModel

...

@Html.ListBoxFor(m => m.SelectedSubscriberIds, Model.SubscriberChoices)

更新

添加转换VB code。这可能无法正常工作100%开箱。任何人都更VB经验可以随意编辑此更正任何问题。

Adding converted VB code. This may not work 100% out of the box. Anyone with more VB experience may feel free to edit this to correct any issues.

视图模型

Public Class GroupViewModel
    ' Group properties you need to edit here

    Public Property SelectedSubscriberIds As List(Of Integer)
    Public Property SubscriberChoices As IEnumerable(Of SelectListItem)

End Class

控制器code

' We'll use this code multiple times so it's factored out into it's own method
Private Sub PopulateSubscriberChoices(model As GroupViewModel)
    model.SubscriberChoices = db.Subscribers.[Select](Function(m) New SelectListItem With { _
        .Value = m.Id, _
        .Text = m.FirstName & " " & m.LastName _
    })
End Sub

Public Function Create() As ActionResult
    Dim model as New GroupViewModel
    PopulateSubscriberChoices(model)
    Return View(model)
End Function

<HttpPost> _
Public Function Create(model As GroupViewModel) As ActionResult
    If ModelState.IsValid Then
        ' Map the posted values onto a new `Group` instance. To set `Subscribers`,
        ' lookup instances from the database using the list of ids the user chose
        Dim group = New Group With { _
            .Name = model.Name, _
            .Subscribers = db.Subscribers.Where(Function(m) model.SelectedSubscriberIds.Contains(m.Id)) _
        }
        db.Groups.Add(group)
        db.SaveChanges()

        Return RedirectToAction("Index")
    End If

    PopulateSubscriberChoices(model)
    Return View(model)
End Function

Public Function Edit(id As Integer) As ActionResult
    Dim group = db.Groups.Find(id)
    If group Is Nothing Then
        Return New HttpNotFoundResult()
    End If

    ' Map `Group` properties to your view model
    Dim model = New GroupViewModel With { _
        .Name = group.Name, _
        .SelectedSubscriberIds = group.Subscribers.[Select](Function(m) m.Id).ToList _
    }

    PopulateSubscriberChoices(model)
    Return View(model)
End Function

<HttpPost> _
Public Function Edit(id As Integer, model As GroupViewModel) As ActionResult
    Dim group = db.Groups.Find(id)
    If group Is Nothing Then
        Return New HttpNotFoundResult()
    End If

    If ModelState.IsValid Then
        group.Name = model.Name

        ' Little bit trickier here
        ' First remove subscribers that are no longer selected
        group.Subscribers.Where(Function(m) Not model.SelectedSubscriberIds.Contains(m.Id)).ToList().ForEach(Function(m) group.Subscribers.Remove(m))

        ' Now add newly selected subscribers
        Dim existingSubscriberIds = group.Subscribers.[Select](Function(m) m.Id)
        Dim newSubscriberIds = model.SelectedSubscriberIds.Except(existingSubscriberIds)
        db.Subscribers.Where(Function(m) newSubscriberIds.Contains(m.Id)).ToList().ForEach(Function(m) group.Subscribers.Add(m))

        db.Entry(group).State = EntityState.Modified
        db.SaveChanges()

        Return RedirectToAction("Index")
    End If

    PopulateSubscriberChoices(model)
    Return View(model)
End Function

这篇关于ASP.NET MVC 5 - 脚手架为多对一的关系的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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