Search code examples
asp.net-mvcasp.net-corerazorentity-framework-core

How to build a form with multiple properties (using IEnumerable or multiple properties in the class) when data ain't already exist?


I'm confused about how I have to build my Model class and the form. To work with two (has the possibility to be more in the future) properties with the same type. I think it's more obviously to use an IEnumerable but when comes to put into a form to work with I can't get a way to do this.

The main idea is to have a student form, where I can define two teachers (math and biology for example) to the student. *Note that I need to always create new teachers for each student, with specific subject and classroom. Not loaded/already created ones.

public class Student
{
   // other properties like Id, Name
   public Teacher MathTeacher { get; set; }
   public Teacher BiologyTeacher { get; set; }

   // or

   public List<Teacher> Teachers { get; set; } 
}

public class Teacher
{
   // other properties like Id, Name
   public int SubjectId { get; set; }
   public int ClassroomId { get; set; }
}

But if I use the two properties I believe Entity Framework can't know the exactly teacher to get after this. So, how can I use the IEnumerable property to read the data from a form like this:

in all <select>s should I use asp-for="???" or which is the right way?

<h6>Math Teacher</h6>
<div class="col-12 col-md-4">
    <label class="form-label">Subject</label>
    <select class="form-select" asp-items="@(new SelectList(Model.Subjects, "Id", "Name"))">
        <option disabled selected>Select the subject</option>
    </select>
</div>
<div class="col-12 col-md-4">
    <label class="form-label">Classroom</label>
    <select class="form-select" asp-items="@(new SelectList(Model.Classrooms, "Id", "Name"))">
        <option disabled selected>Select the classroom</option>
    </select>
</div>

<h6>Biology Teacher</h6>
<div class="col-12 col-md-4">
    <label class="form-label">Subject</label>
    <select class="form-select" asp-items="@(new SelectList(Model.Subjects, "Id", "Name"))">
        <option disabled selected>Select the subject</option>
    </select>
</div>
<div class="col-12 col-md-4">
    <label class="form-label">Classroom</label>
    <select class="form-select" asp-items="@(new SelectList(Model.Classrooms, "Id", "Name"))">
        <option disabled selected>Select the classroom</option>
    </select>
</div>

I want to get a model loaded like this after submit the form:

student:

  • id: 3
  • name: 'aaaaa'
  • teachers:
    • id 1, name: 'xxxx', subjectId: 3, classroomId: 1,
    • id 3, name: 'zzzz', subjectId: 54, classroomId: 1

or with the purpose of two properties?

student:

  • id: 3
  • name: 'aaaaa'
  • mathTeacher: id 1, name: 'xxxx', subjectId: 3, classroomId: 1,
  • biologyTeacher: id 3, name: 'zzzz', subjectId: 54, classroomId: 1

I just can't get any example of how get something similar.


Solution

  • But if I use the two properties I believe Entity Framework can't know the exactly teacher to get after this

    Two properties can be bound and distinguish successfully actually.

    Here is a working demo you could follow:

    Model

    public class Student
    {
        // other properties like Id, Name
        public Teacher MathTeacher { get; set; }
        public Teacher BiologyTeacher { get; set; }
    
        public List<Subject> Subjects { get; set; }
        public List<Classroom> Classrooms { get; set; }
    }
    public class Subject
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
    public class Classroom
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
    public class Teacher
    {
        // other properties like Id, Name
        public int SubjectId { get; set; }
        public int ClassroomId { get; set; }
    }
    

    View(Create.cshtml)

    @model Student
    <h6>Math Teacher</h6>
    <form method="post" asp-action="Create">
        <div class="col-12 col-md-4">
            <label class="form-label">Subject</label>
            <select class="form-select" asp-for="MathTeacher.SubjectId" asp-items="@(new SelectList(Model.Subjects, "Id", "Name"))">
                <option disabled selected>Select the subject</option>
            </select>
        </div>
        <div class="col-12 col-md-4">
            <label class="form-label">Classroom</label>
            <select class="form-select" asp-for="MathTeacher.ClassroomId" asp-items="@(new SelectList(Model.Classrooms, "Id", "Name"))">
                <option disabled selected>Select the classroom</option>
            </select>
        </div>
    
        <h6>Biology Teacher</h6>
        <div class="col-12 col-md-4">
            <label class="form-label">Subject</label>
            <select class="form-select" asp-for="BiologyTeacher.SubjectId" asp-items="@(new SelectList(Model.Subjects, "Id", "Name"))">
                <option disabled selected>Select the subject</option>
            </select>
        </div>
        <div class="col-12 col-md-4">
            <label class="form-label">Classroom</label>
            <select class="form-select" asp-for="BiologyTeacher.ClassroomId" asp-items="@(new SelectList(Model.Classrooms, "Id", "Name"))">
                <option disabled selected>Select the classroom</option>
            </select>
        </div>
        <input type="submit" value="Post"/>
    </form>
    

    Controller

    Note: Hard-coded the data here for easy testing, you can get the data from database by yourself.

    [HttpGet]
    public IActionResult Create()
    {
        //hard-coded for easy testing....
        //set the value for the selectlist
        var model = new Student()
        {
            Subjects = new List<Subject>()
            {
                new Subject(){Id=1,Name="sub1"},
                new Subject(){Id=2,Name="sub2"},
                new Subject(){Id=3,Name="sub3"}
            },
            Classrooms = new List<Classroom>()
            {
                new Classroom(){Id=1,Name="room1"},
                new Classroom(){Id=2,Name="room2"},
                new Classroom(){Id=3,Name="room3"}
            }
        };
        return View(model); 
    }
    [HttpPost]
    public IActionResult Create(Student model)
    {
        //do your stuff....
        return View();
    }