Search code examples
entity-frameworkasp.net-corerazor-pages

Posting multiple select list items to database with Asp.net Core Razor Pages


I am wanting to post all selected items from a list to a table, creating a new row for each of the selected items. I am having trouble posting multiple items at once however. I have tried to set up the tables to have a relationship using navigation properties but im rather new at this so cannot be sure where I have gone wrong. Currently I am able to post to the database, but only 1 record. The sticking point is posting multiple records to the TblReferrals table.

Please see below my model and page model set ups, so far

 public class TblReferrals
 {

     [Key]
     public string? IncidentId { get; set; }

     public string AssignmentNumber { get; set; } 
}

public class TblReferralStaff
{   
    public int Id { get; set; }

    public string? AssignmentNumber { get; set; }

    public TblReferrals TblReferrals { get; set; }

    public string? IncidentId { get; set; }

}

My form

 <form method="post" id="newReferralForm">
    
     <div class="row my-md-3">
         <div class="col-md-6">
             <label>Staff Names</label>                 
             <select class="form-control staffReferral" multiple="multiple" asp-items="@Model.EsrRecords" asp-for="@Model.ReferralStaff.AssignmentNumber">
                 <option></option>
             </select>
         </div>               
     </div>           
     <div class="row my-md-3">              
         <div class="col-md-6">
             <label>Incident Number</label>
             <input class="form-control" asp-for="@Model.Referral.IncidentId" />
         </div>
     </div>
  
     <div class="d-flex justify-content-center mt-5">
         <button class="btn btn-primary fw-bold createReferral">Submit</button>
     </div>
 </form>

My Post request which is not complete, as this is the bit im kind of getting stuck on

   [BindProperty]
   public List<string> TblStaffList { get; set; }

   public SelectList EsrRecords { get; set; }

   public async Task<IActionResult> OnPostNewReferral()
   {


       await _db.TblReferralStaff.AddRangeAsync(ReferralStaff);

       await _db.TblReferrals.AddAsync(Referral);
       await _db.SaveChangesAsync();

       return new JsonResult(ReferralStaff);


   }

Solution

  • From your code and description, You are setting a one-to-many relationship in your models https://learn.microsoft.com/en-us/ef/core/modeling/relationships/one-to-many . Here is the modification.

    1 The configuration of your models and dbcontext

    Tbl Model

    public class TblReferrals
    {
        [Key]
        public string? IncidentId { get; set; }
        public string AssignmentNumber { get; set; }
        public ICollection<TblReferralStaff> TblReferralStaffs { get; } = new List<TblReferralStaff>();
    }
    
    public class TblReferralStaff
    {
        public int Id { get; set; }
        public string? AssignmentNumber { get; set; }
        public TblReferrals TblReferrals { get; set; } = null!;
        public string? IncidentId { get; set; }
    }
    

    DbContext

    public class MultipleRecordsContext : DbContext
    {
        public MultipleRecordsContext (DbContextOptions<MultipleRecordsContext> options)
            : base(options)
        {
        }
    
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<TblReferrals>()
                .HasMany(e => e.TblReferralStaffs)
                .WithOne(e => e.TblReferrals)
                .HasForeignKey(e => e.IncidentId)
                .IsRequired();
        }
    
        public DbSet<MultipleRecords.Models.TblReferrals> TblReferrals { get; set; } = default!;
        public DbSet<MultipleRecords.Models.TblReferralStaff> TblReferralStaff { get; set; } = default!;
    }
    

    It will generate two tables for you in database, and add the foreign key reference.

    2 Bind the correct value in your razor pages

    Tbl.cshtml

    @page
    @model MultipleRecords.Pages.TblModel
    @{
    }
    
    <h1>This is TblReferrals</h1>
    
    <form method="post" id="newReferralForm">
    
        <div class="row my-md-3">
            <div class="col-md-6">
                <label>Staff Names</label>
                @* For a clearer display, I directly popup the option value with numbers *@
                @* Here is the TblStaffList that is bound *@
                <select class="form-control staffReferral" multiple="multiple" asp-items="@Model.EsrRecords" asp-for="@Model.TblStaffList">
                    <option value="1"> Num 1 </option>
                    <option value="2"> Num 2 </option>
                    <option value="3"> Num 3 </option>
                    <option value="4"> Num 4 </option>
                </select>
            </div>
        </div>
        <div class="row my-md-3">
            <div class="col-md-6">
                <label>Incident Number</label>
                <input class="form-control" asp-for="@Model.Referral.IncidentId" />
            </div>
        </div>
    
        <div class="d-flex justify-content-center mt-5">
            <button class="btn btn-primary fw-bold createReferral">Submit</button>
        </div>
    </form>
    

    Tbl.cshtml.cs

    public class TblModel : PageModel
    {
        private readonly MultipleRecordsContext _db;
    
        public TblModel(MultipleRecordsContext db)
        {
            _db = db;
        }
        public void OnGet()
        {
        }
    
        [BindProperty]
        public TblReferrals Referral { get; set; }
    
        [BindProperty]
        public List<string> TblStaffList { get; set; }
    
        public SelectList EsrRecords { get; set; }
    
        public async Task<IActionResult> OnPostAsync()
        {
            Console.WriteLine("Post entered");
    
            //Considered that the <select> element with multiple="multiple" attribute can only bind to a list of simple types,
            //it is clearer to bind the value to a string list and initialize a referralstaff object
            
            //Your logic code
            …
            await _db.TblReferrals.AddAsync(referral);
            await _db.SaveChangesAsync();
    
            // Create a referral staff record for each selected staff number member.
            foreach (var staffAssignmentNumber in TblStaffList)
            {
                var referralStaff = new TblReferralStaff
                {
                    AssignmentNumber = staffAssignmentNumber,
                    IncidentId = Referral.IncidentId
                };
                await _db.TblReferralStaff.AddAsync(referralStaff);
            }
    
            await _db.SaveChangesAsync(); // Save referral staff records.
    
            return RedirectToPage("Index");
    
        }
    }
    

    Option selected

    enter image description here

    Value passed

    enter image description here

    Records stored

    enter image description here