2013-07-23 2 views
3

Je travaille avec ASP.NET MVC 4 et Entity Framework et je cherchais un moyen de faire beaucoup de relation et de cases à cocher de mon db pour un Créer/Modifier le contrôleur et afficher, j'ai trouvé la réponse avec réponse @Slauma pour créer dans MVC 4 - Many-to-Many relation and checkboxes mais, j'aimerais vraiment voir comment cela s'étend à la fonctionnalité Modifier et supprimer ainsi que d'autres partenaires dans cette solution. Quelqu'un pourrait-il montrer comment je remplirais le ClassificationSelectViewModel dans la méthode Edit controller pour obtenir les valeurs "checked" et "unchecked"? C'est une question de Matt Flowers qui va résoudre le mien aussi.MVC 4 Edit Contrôleur/Voir plusieurs à plusieurs relations et cases à cocher

+0

Pouvez-vous nous montrer ce que vous avez déjà fait? – Jack

+0

@Jack: Fondamentalement, le schéma create model/view/controller du lien, avec quelques petites exceptions et ce dont j'ai besoin est la méthode Edit, je suppose que je ne peux pas ajouter autre chose que vous ne pouvez pas voir là-bas – JamesT

Répondre

10

Ce qui suit est une continuation de this answer qui décrit Create actions GET et POST pour un modèle avec plusieurs à plusieurs entre entités Subscription et Company. Voici la procédure pour les Edit actions que je le ferais (sauf que je ne serait probablement pas mettre tout le code EF dans les actions du contrôleur, mais l'extraire dans des méthodes d'extension et de service):

le CompanySelectViewModel reste inchangé:

public class CompanySelectViewModel 
{ 
    public int CompanyId { get; set; } 
    public string Name { get; set; } 
    public bool IsSelected { get; set; } 
} 

le SubscriptionEditViewModel est le SubscriptionCreateViewModel ainsi que la 'propriété clé de:

public class SubscriptionEditViewModel 
{ 
    public int Id { get; set; } 
    public int Amount { get; set; } 
    public IEnumerable<CompanySelectViewModel> Companies { get; set; } 
} 

L'action GET pourrait ressembler à ceci:

public ActionResult Edit(int id) 
{ 
    // Load the subscription with the requested id from the DB 
    // together with its current related companies (only their Ids) 
    var data = _context.Subscriptions 
     .Where(s => s.SubscriptionId == id) 
     .Select(s => new 
     { 
      ViewModel = new SubscriptionEditViewModel 
      { 
       Id = s.SubscriptionId 
       Amount = s.Amount 
      }, 
      CompanyIds = s.Companies.Select(c => c.CompanyId) 
     }) 
     .SingleOrDefault(); 

    if (data == null) 
     return HttpNotFound(); 

    // Load all companies from the DB 
    data.ViewModel.Companies = _context.Companies 
     .Select(c => new CompanySelectViewModel 
     { 
      CompanyId = c.CompanyId, 
      Name = c.Name 
     }) 
     .ToList(); 

    // Set IsSelected flag: true (= checkbox checked) if the company 
    // is already related with the subscription; false, if not 
    foreach (var c in data.ViewModel.Companies) 
     c.IsSelected = data.CompanyIds.Contains(c.CompanyId); 

    return View(data.ViewModel); 
} 

La vue Edit est la vue Create plus un champ caché pour les Subscription' Subscription s propriété clé Id:

@model SubscriptionEditViewModel 

@using (Html.BeginForm()) { 

    @Html.HiddenFor(model => model.Id) 
    @Html.EditorFor(model => model.Amount) 

    @Html.EditorFor(model => model.Companies) 

    <input type="submit" value="Save changes" /> 
    @Html.ActionLink("Cancel", "Index") 
} 

L'éditeur mplate pour sélectionner une entreprise reste inchangée:

@model CompanySelectViewModel 

@Html.HiddenFor(model => model.CompanyId) 
@Html.HiddenFor(model => model.Name) 

@Html.LabelFor(model => model.IsSelected, Model.Name) 
@Html.EditorFor(model => model.IsSelected) 

Et l'action POST pourrait ressembler à ceci:

[HttpPost] 
public ActionResult Edit(SubscriptionEditViewModel viewModel) 
{ 
    if (ModelState.IsValid) 
    { 
     var subscription = _context.Subscriptions.Include(s => s.Companies) 
      .SingleOrDefault(s => s.SubscriptionId == viewModel.Id); 

     if (subscription != null) 
     { 
      // Update scalar properties like "Amount" 
      subscription.Amount = viewModel.Amount; 
      // or more generic for multiple scalar properties 
      // _context.Entry(subscription).CurrentValues.SetValues(viewModel); 
      // But this will work only if you use the same key property name 
      // in ViewModel and entity 

      foreach (var company in viewModel.Companies) 
      { 
       if (company.IsSelected) 
       { 
        if (!subscription.Companies.Any(
         c => c.CompanyId == company.CompanyId)) 
        { 
         // if company is selected but not yet 
         // related in DB, add relationship 
         var addedCompany = new Company 
          { CompanyId = company.CompanyId }; 
         _context.Companies.Attach(addedCompany); 
         subscription.Companies.Add(addedCompany); 
        } 
       } 
       else 
       { 
        var removedCompany = subscription.Companies 
         .SingleOrDefault(c => c.CompanyId == company.CompanyId); 
        if (removedCompany != null) 
         // if company is not selected but currently 
         // related in DB, remove relationship 
         subscription.Companies.Remove(removedCompany); 
       } 
      } 

      _context.SaveChanges(); 
     } 

     return RedirectToAction("Index"); 
    } 

    return View(viewModel); 
} 

Les Delete actions sont moins difficiles. Dans l'action GET vous pouvez charger quelques propriétés de l'abonnement pour afficher sur la vue de la confirmation de suppression:

public ActionResult Delete(int id) 
{ 
    // Load subscription with given id from DB 
    // and populate a `SubscriptionDeleteViewModel`. 
    // It does not need to contain the related companies 

    return View(viewModel); 
} 

Et dans l'action POST que vous chargez l'entité et le supprimer ensuite. Il n'y a pas besoin d'inclure les entreprises parce que dans un grand nombre à plusieurs rapports (généralement) suppression en cascade sur la table de lien est activé afin que la base de données se chargera de supprimer les entrées de lien avec le parent Subscription:

[HttpPost, ActionName("Delete")] 
public ActionResult DeleteConfirm(int id) 
{ 
    var subscription = _context.Subscriptions.Find(id); 
    if (subscription != null) 
     _context.Subscriptions.Remove(subscription); 

    return RedirectToAction("Index"); 
} 
+0

très bonne réponse! J'ai dû faire un petit changement cependant. J'ai dû changer data.ViewModel.Companies.ForEach ( c => {c.IsSelected = data.CompanyIds.Contains (c.CompanyId);}); à foreach (var c dans data.ViewModel.Entreprises) { c.IsSelected = data.CompanyIds.Contains (c.CompanyID); } (Désolé pour le mauvais format de commentaire.) –

+0

@MattFlowers: Ah, c'est vrai, j'ai corrigé ça. Merci! – Slauma

+0

@Slauma Hey question stupide ce que le code semble l ike sur la vue (avec des cases à cocher ... +1 très utile ce que je veux dire est que lorsque j'utilise 'CompanySelectViewModel' à mon avis, je reçois ** Erreur **' l'élément de modèle passé dans le dictionnaire est de type' car il attend 'SubscriptionEditViewModel' –

Questions connexes