4 votes

Aide avec la liaison de modèle imbriquée asp.net mvc

Donc j'ai ce projet de démo presque entièrement fonctionnel.

public class Project
    {
        public int ID { get; set; }
        [Required]
        public string Name { get; set; }
        public virtual ICollection Tasks { get; set; }

    }

    public class Task
    {
        public int ID { get; set; }
        [Required]
        public string Name { get; set; }
        public int ProjectID { get; set; }

        public virtual Project Project { get; set; }

    }

Contrôleur

public ActionResult Edit(int id)
        {           
            var project = db.Projects.Where(p=>p.ID==id).Single();
            return View(project);
        }

        [HttpPost]
        public ActionResult Edit(Project project)
        {
            if (ModelState.IsValid)
            {
                var dbProject = db.Projects.Where(p => p.ID == project.ID).Single();

                UpdateModel(dbProject);
                db.SaveChanges();                
                TempData["Success"] = "Modèle Valide";
            }
            return RedirectToAction("Index");
        }

Vue//fortement typée pour le projet

@using (Html.BeginForm())
{
    @Html.ValidationSummary(true)

        Project
        @Html.HiddenFor(model => model.ID)

            @Html.LabelFor(model => model.Name)

            @Html.EditorFor(model => model.Name)
            @Html.ValidationMessageFor(model => model.Name)

        Tâches
        @Html.EditorFor(m => m.Tasks)

}

Modèle d'Éditeur

@model MvcApplication2.Models.Task
Tâche

    @Html.LabelFor(m => m.Name)
    @Html.EditorFor(m => m.Name)
    @Html.HiddenFor(m => m.ID)
    @Html.HiddenFor(m => m.ProjectID)
    @Html.ValidationMessageFor(m => m.Name)

La vue affiche cela

entrez la description de l'image ici

Le problème est que lorsque je soumets le formulaire, les Tâches sont remplies avec tout sauf la propriété virtuelle Project... donc l'erreur que je reçois est

L'opération a échoué : La relation n'a pas pu être modifiée car l'une ou plusieurs des propriétés de clé étrangère sont non nullables. Lorsqu'une modification est apportée à une relation, la propriété de clé étrangère associée est définie sur une valeur nulle. Si la clé étrangère ne supporte pas les valeurs nulles, une nouvelle relation doit être définie, la propriété de clé étrangère doit se voir assigner une autre valeur non nulle, ou l'objet non lié doit être supprimé.

Voici une capture d'écran du résultat de mon point d'arrêt de débogage

entrez la description de l'image ici

S'il vous plaît Aidez-moi.

MISE À JOUR :

J'ai changé mon action de contrôleur comme ceci

[HttpPost]
        public ActionResult Edit(Project project)
        {
            if (ModelState.IsValid)
            {
                db.Entry(project).State = EntityState.Modified;
                db.SaveChanges();                
                TempData["Success"] = "Modèle Valide";
                return RedirectToAction("Index");
            }
            return View(project);
        }

cela ne fonctionne toujours pas correctement. Maintenant, les changements apportés au Nom du projet sont mis à jour correctement dans la base de données. mais les changements apportés à n'importe quel Nom de Tâche sont complètement ignorés.

4voto

Je crois que @Html.EditorFor(m => m.Tasks) génère du html comme suit (approximativement)

Nom

Au-dessus se trouve le html approximatif généré pour la première tâche dans la collection et un html similaire sera généré pour chaque tâche de la collection. La seule différence est que l'index sera incrémenté dans les attributs de nom de tous les inputs, c'est-à-dire Tasks[1].Name, Tasks[1].ProjectID, etc. Cette portion se liera en réalité à la propriété Collection Tasks de Project, mais vous pouvez voir que dans la portion détaillée, vous n'avez aucun input comme

Le Modelbinder a besoin d'éléments d'entrée avec des conventions de nommage appropriées pour lier les valeurs à toutes les propriétés des paramètres de la méthode d'action. À des fins de test, vous pouvez inclure ces deux lignes dans votre modèle d'éditeur pour Task

@Html.TextBoxFor(x=>x.Project.ID)
@Html.TextBoxFor(x=>x.Project.Name)

Entrez des valeurs appropriées pour eux dans le formulaire et la propriété Project de Task sera remplie avec ces valeurs. Mais cela peut ne pas être ce que vous désirez, c'est-à-dire entrer les informations du projet deux fois et cela peut ne pas être nécessaire (si vous utilisez Linq to SQL, ce n'est certainement pas nécessaire). Lorsque vous appelez votre ORM pour attacher des entités aux entités db, il saura à quel élément Project la tâche actuelle appartient.
Note latérale: Lorsque vous rencontrez des problèmes avec la liaison du modèle, faites toujours attention au html généré. Le html généré dictera quelles valeurs de formulaire se mapperont à quelles propriétés du modèle tant que vous utilisez le ModelBinder par défaut. Cela devient particulièrement important si vous avez un scénario de type maître détail comme dans votre exemple.

1voto

ignaciofuentes Points 1526

J'ai trouvé un moyen de faire fonctionner cela, mais je ne suis pas entièrement satisfait de l'approche.

Consultez cette question sur la façon de refactoriser mon code actuel pour voir comment je le fais actuellement (espérons-le temporairement)

Aidez à améliorer (refactoriser) mon code. Automapper - EF - asp.net mvc-3

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X