ASP.NET MVC 5 - 多对一关系的脚手架

Ruc*_*pta 1 asp.net-mvc entity-framework one-to-many many-to-one asp.net-mvc-scaffolding

我正在使用VS 2013开发ASP.NET MVC 5,EF 6,Razor Engine,VB语言和数据库第一种方法.

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

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

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
)
Run Code Online (Sandbox Code Playgroud)

现在,当我使用脚手架自动生成控制器和视图时; 我Group在"创建订阅者"和"编辑订阅者"视图中得到一个<select>控件(所有项目都在<option>里面).

但实际上,我希望"创建组"和"编辑组"视图向我询问我Subscribers想要添加到特定组中.对于相同的HTML控制可以是复选框的列表<选择多个="多个">与所有Subscriber的项目,如<选项>秒.

我该如何自动生成/实现它?

Chr*_*att 6

不要过分依赖脚手架.重点在于它为您提供了工作的基础; 对你的观点来说,这不是万能的.您可以而且应该修改脚手架以满足您的需求,老实说,通常情况下,从头开始比尝试撤消脚手架增加的所有不必要的绒毛更容易.

也就是说,特别是在一次选择多个相关项目时,您需要一个视图模型.试图使用你的实体来快速耗尽.所以创建一个类,如:

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

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

    public IEnumerable<SelectListItem> SubscriberChoices { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

然后,在你的控制器中:

// 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);
}
Run Code Online (Sandbox Code Playgroud)

编辑后期操作是最困难的.为了不会出现有关重复键等的错误,您需要确保不要将重复项添加到集合中.您还需要确保删除此组与用户取消选择的任何项之间的关系.除此之外,它非常直接.

最后在您的视图中,您只需要渲染选择列表:

@model Namespace.To.GroupViewModel

...

@Html.ListBoxFor(m => m.SelectedSubscriberIds, Model.SubscriberChoices)
Run Code Online (Sandbox Code Playgroud)

UPDATE

添加转换的VB代码.这可能无法100%开箱即用.任何具有更多VB经验的人都可以随意编辑以纠正任何问题.

查看模型

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
Run Code Online (Sandbox Code Playgroud)

控制器代码

' 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
Run Code Online (Sandbox Code Playgroud)