1

Я работаю на ASP.NET MVC 5, 6, EF Razor Engine, VB языка и базы данных Первый подход с VS 2013.ASP.NET MVC 5 - Строительные леса для многих к одному Отношения

Теперь в моей БД ; У меня есть две таблицы, как показано ниже:

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 
) 

Теперь, когда я автоматическую генерацию контроллеров и представлений с помощью Леса строительные; Я получаю <. Выберите > элемент управления (со всеми Group элементами как < вариант > внутри) в представлениях «Создать подписчика» и «Изменить подписчика».

Но на самом деле, я хочу, чтобы «Создать группу» и «Изменить группу», чтобы задать мне Subscribers Я хочу добавить в конкретную группу. Контроль HTML для того же может быть списка флажка или < выбрать несколько = «несколько» > со всеми Subscriber элементов как < варианта > с.

Как я могу создать или реализовать это?

ответ

6

Не полагайтесь слишком сильно на леса. Все дело в том, что он дает вам базу для работы; это не все, что вам нужно. Вы можете и должны модифицировать строительные леса в соответствии с вашими потребностями, и, честно говоря, чаще всего легче начинать с нуля, чем пытаться отменить все ненужные пушистые добавления.

Сказанное, особенно при выборе нескольких связанных предметов сразу, вы необходимо модель. Попытка использовать вашу сущность для этого быстро выйдет из строя. Так создать класс, как:

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

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

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

Затем в контроллере:

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

Редактирование после действия является самым трудным. Чтобы не получить ошибок в дублирующих ключах и т. Д., Вам необходимо убедиться, что вы не добавляете в коллекцию дубликаты. Вам также необходимо убедиться, что вы удаляете связь между этой группой и любыми элементами, которые пользователь не выбрал. Кроме этого, это довольно прямолинейно.

Наконец, в ваших взглядах, вы просто нужно, чтобы сделать список выбора:

@model Namespace.To.GroupViewModel 

... 

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

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 

Controller Код

' 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 
+0

Спасибо за помощь ... Но придется преобразовать его в VB, чтобы проверить, работает ли он в моем коде или нет. Я не C# парень ... :( –

+1

Извините, но я полностью пропустил часть VB, но я не парень VB, поэтому мой ответ не мог быть таким полным. Вы должны быть в состоянии получить больше в том, что там просто используется что-то вроде http://converter.telerik.com/ –

+1

Добавлен конвертированный код VB. Он может не работать без изменений, но он подойдет вам хотя бы ближе. –

Смежные вопросы