4
votes

ASP.NET CORE MVC SelectList à partir d'une collection d'objets

J'ai donc ces 2 classes représentant des tables dans une base de données locale à l'aide de la migration de base ef dans une application de base asp.net

<form asp-action="Create">
        <div asp-validation-summary="ModelOnly" class="text-danger"></div>
        <div class="form-group">
            <label asp-for="Teacher" class="control-label"></label>
            <select asp-for="Teacher" class ="form-control" asp-items="ViewBag.Teachers"></select>
        </div>
        <div class="form-group">
            <label asp-for="Name" class="control-label"></label>
            <input asp-for="Name" class="form-control" />
            <span asp-validation-for="Name" class="text-danger"></span>
        </div>
        <div class="form-group">
            <input type="submit" value="Create" class="btn btn-default" />
        </div>
    </form>

et

    public IActionResult Create()
    {
        var teachers = from s in _context.Teachers
                           where s.Class == null
                           select s;

        ViewData["Teachers"] = new SelectList(teachers.ToList());
        return View();
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Create(Class @class)
    {
        if (ModelState.IsValid)
        {
            @class.TeacherID = @class.Teacher.ID;
            _context.Add(@class);
            await _context.SaveChangesAsync();
            return RedirectToAction(nameof(Index));
        }
        return View("Index");
    }

Je veux ajouter dans mon contrôleur de classes la fonctionnalité pour créer une nouvelle instance de la classe "Classe" en tapant un nom dans une zone de texte et en sélectionnant un enseignant dans une liste déroulante.

Voici mon créer des méthodes http get & post

public class Class
{
    public int ID { get; set; }

    public int TeacherID { get; set; }

    public string Name { get; set; }


    public Teacher Teacher { get; set; }

    public ICollection<Student> Students { get; set; }
}

et le formulaire de soumission de données saisies par l'utilisateur

public class Teacher
{
    public int ID { get; set; }

    public string FistName { get; set; }

    public string LastName { get; set; }

    public Class Class { get; set; }

    public string FullName
    {
        get
        {
            return $"{LastName} {FistName}";
        }
    }

    public override string ToString()
    {
        return FullName;
    }
}

Je vois le bon données dans la liste déroulante mais pour une raison quelconque dans la méthode POST @ class.Teacher est nul. Qu'est-ce que je fais mal?


0 commentaires

4 Réponses :


0
votes

Une liste de sélection ne renverra qu'un type primitif (string, int, etc.), pas une instance de classe entière. En conséquence, vous devrez lier la valeur à une propriété qui est également un type primitif. Puisque vous avez déjà une propriété TeacherID , vous pouvez simplement l'utiliser. Lorsque vous enregistrez, EF corrigera la référence Teacher avec l'ID correspondant.

<select asp-for="TeacherID" class ="form-control" asp-items="ViewBag.Teachers"></select>


2 commentaires

Ok, je l'ai fait, mais maintenant ModelState.IsValid est désactivé et si j'utilise le débogueur, je peux voir que la valeur TeacherID dans la méthode POST est 0, même si mon enseignant sélectionné a un ID de 2


et c'est parce que l'élément sélectionné dans la liste déroulante se traduit en une chaîne .. et ensuite il essaie de le mapper à la propriété TeacherID qui est un int. Existe-t-il un moyen d'afficher la propriété du nom complet dans la liste déroulante mais de mapper correctement l'identifiant de l'enseignant?



0
votes

"Teacher" est une classe complexe, qui sera toujours nulle, je pense que vous êtes confus, remplacez "Teacher" par "teacherID" . EF fera le travail.


0 commentaires

3
votes

Commencez par mettre à jour votre méthode Create GET comme suit:

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(Class @class)
{
    if (ModelState.IsValid)
    {
        _context.Classes.Add(@class); // now your @class is containing the `TeacheID` value selected from drop-down.
        await _context.SaveChangesAsync();
        return RedirectToAction(nameof(Index));
    }
    return View("Index");
}

Ensuite, écrivez votre FormGroup pour sélectionnez la liste comme suit:

<div class="form-group">
     <label asp-for="TeacherID" class="control-label">Teacher</label>
     <select asp-for="TeacherID" class ="form-control" asp-items="ViewBag.Teachers">
     </select>
     <span asp-validation-for="TeacherID" class="text-danger"></span>
</div>

Maintenant, mettez à jour votre méthode Create POST comme suit:

public async Task<IActionResult> Create()
{
    var teachers = await _context.Teachers.Where(t => t.Class == null).ToListAsync();
    ViewData["Teachers"] = new SelectList(teachers,"ID","FullName");
    return View();
}

Maintenant, tout devrait bien fonctionner!


0 commentaires

1
votes

Apportez les modifications suivantes

Créez la méthode http get, affichez SelectList Class , définissez ID sur le dataValueField de la selectList et définissez FullName code > au dataTextField de selectList

<select asp-for="TeacherID" class="form-control" asp-items="ViewBag.Teachers"></select>

La balise de sélection dans le formulaire

 public IActionResult Create()
    {
        var teachers = from s in _context.Teacher
                       where s.Class == null
                       select s;

        ViewData["Teachers"] = new SelectList(teachers.ToList(),"ID","FullName");
        return View();
    }


0 commentaires