locked
Select Asp-items not adding data to database. RRS feed

  • Question

  • User1153554953 posted

    Hello, I have been having really strange issue with asp-items, I am using ViewBag to pass a List<SelectListItem> object to asp-items but in return, it's not adding anything to my database, even though when I see the source through browser it shows every value and text of Select option fine. The select asp-items is as follows and "Manufacturers" is actually a foreign key in "Dinghies" Table.

    div class="form-group">
                <label asp-for="Manufacturers" class="control-label"></label>
                <select class="form-control" asp-for="Manufacturers" asp-items="ViewBag.Manufacturers"></select>
                <span asp-validation-for="Manufacturers"></span>
            </div>

    Let me explain more, Here are some of the controller methods against the form mentioned above

    public IActionResult AddDinghies() {
                List<SelectListItem> List1 = new List<SelectListItem>();
                List1 = SelectListConverter(_context3.Manufacturers); //.ToList()
                ViewBag.Manufacturers = List1;
                return View();
            }
    //Method to Convert IEnumerable to SelectListItem
    private List<SelectListItem> SelectListConverter(IEnumerable<Manufacturers> Manufacturers)
            {
                List<SelectListItem> ListOfMan = new List<SelectListItem>();
                foreach (var manufacturer in Manufacturers)
                {
                    ListOfMan.Add(new SelectListItem
                    {
                        Value = manufacturer.id.ToString(),
                        Text = manufacturer.Manufacturer //Name of manufacturer
                    });
                }
                return ListOfMan;
         }
    
    [HttpPost]
            [ValidateAntiForgeryToken]
            public async Task<IActionResult> AddDinghies([Bind("id,Name,OlympicBoat,Type,TypeCrew,TypePurpose,Length,Beam,Draft,SailAreaUpwind,GennakerSailArea,SpinnakerSailArea,SAOptional,SAOptional2,Weight,PYS,ImagePath,CrewPersons,CrewWeight,Description,DesignBy,DesignYear,OlympicSectionViewSwitch,Manufacturersid")] Dinghies dg)
            {
                if (ModelState.IsValid)
                {
                    _context2.Add(dg);
                    await _context2.SaveChangesAsync();
                    return RedirectToAction(nameof(Index));
                }
                return View(dg);
            }

    Actually whats wrong is happening within this code is that every entity from the View form is being passed to the "Dinghy" table but the Manufacturersid which is the foreign key and is being passed from asp-items always remains empty/null. 

    Any help or hint will be highly appreciated, I can provide more explanation/code if anybody wants. I know its tough to read this much code but I really need help in this. Thanks a lot! 

    Thursday, August 27, 2020 5:23 PM

Answers

  • User-17257777 posted

    Hi najum98,

    Since you need receive the ManufacturerID, you should define it in the Dinghies class, and set it as the ForeignKey. And you should use            asp-for="ManufacturerID" in the select tag, so you can bind the Id value to ManufacturerID. Tested with the below codes:

    Model:

    public class Manufacturers
    {
        [Key]
        public int Id { get; set; }
        public string Name { get; set; }
        public string Address { get; set; }
    }
    
    public class Dinghies
    {
        public int Id { get; set; }
        public string Name { get; set; }
        [ForeignKey("Manufacturers")]
        public int ManufacturerID { get; set; }
        public Manufacturers Manufacturers { get; set; }
    }

    View:

    @model Dinghies
    @{
        ViewData["Title"] = "Home Page";
    }
    <form asp-action="AddDinghies" method="post">
        <div class="form-group">
            <label asp-for="Name" class="control-label"></label>
            <input class="form-control" asp-for="Name" />
            <span asp-validation-for="Name"></span>
        </div>
        <div class="form-group">
            <label asp-for="ManufacturerID" class="control-label"></label>
            <select class="form-control" asp-for="ManufacturerID" asp-items="ViewBag.Manufacturers"></select>
            <span asp-validation-for="ManufacturerID"></span>
        </div>
        <input type="submit" value="submit" class="btn btn-danger" />
    </form>

    Controller:

    public IActionResult Index()
    {
        var Manufacturers = _context.Manufacturers.ToList();
        List<SelectListItem> ListOfMan = new List<SelectListItem>();
        foreach (var manufacturer in Manufacturers)
        {
            ListOfMan.Add(new SelectListItem
            {
                Value = manufacturer.Id.ToString(),
                Text = manufacturer.Name //Name of manufacturer
            });
        }
        ViewBag.Manufacturers = ListOfMan;
        return View();
    }
    
    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> AddDinghies([Bind("Id,Name,ManufacturerID")] Dinghies dg)
    {
        if (ModelState.IsValid)
        {
            _context.Dinghies.Add(dg);
            await _context.SaveChangesAsync();
            return RedirectToAction(nameof(Index));
        }
        return View(dg);
    }

    Result:

    Best Regards,

    Jiadong Meng

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Friday, August 28, 2020 6:58 AM

All replies

  • User-474980206 posted

    The select should map to the Manufacturers ID column not the entity.

    Thursday, August 27, 2020 5:36 PM
  • User1153554953 posted

    Thank you bruce for your contribution but I've already tried this but this is giving me the following error.

    "Dinghies" does not contain a definiton for "Manufacturersid" and no accessible extension method "Manufacturersid".....

    This is pretty strange because I have a column named Manufacturersid in Dinghies table, though Manufacturers is not available. For further reference, this is my Dinghie.cs file 

    using Microsoft.EntityFrameworkCore;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using System.ComponentModel;
    using System.ComponentModel.DataAnnotations;
    using System.ComponentModel.DataAnnotations.Schema;
    
    namespace Dinghysailing.info.Models
    {
        public class Dinghies
        {
            [Key]
            public int id { get; set; }
    
            [Column(TypeName = "nvarchar(50)")]
            [Required(ErrorMessage = "This field is required")]
            [DisplayName("Name: ")]
            public string Name { get; set; }
    
            [Column(TypeName = "nvarchar(50)")]
            [Required(ErrorMessage = "This field is required")]
            [DisplayName("Type: ")]
            public string Type { get; set; }
    
            [Column(TypeName = "nvarchar(50)")]
            [DisplayName("Type Crew")]
            public string TypeCrew { get; set; }
    
            [Column(TypeName = "nvarchar(50)")]
            [DisplayName("Type Purpose")]
            public string TypePurpose { get; set; }
    
            [Column(TypeName = "nvarchar(50)")]
            [DisplayName("Length: ")]
            public string Length { get; set; }
    
            [Column(TypeName = "nvarchar(50)")]
            [DisplayName("Beam")]
            public string Beam { get; set; }
    
            [Column(TypeName = "nvarchar(10)")]
            [DisplayName("Draft")]
            public string Draft { get; set; }
    
            [Column(TypeName = "nvarchar(MAX)")]
            [DisplayName("Sail Area Upwind")]
            public string SailAreaUpwind { get; set; }
    
            [Column(TypeName = "nvarchar(50)")]
            [DisplayName("Gennaker Sail Area ")]
            public string GennakerSailArea { get; set; }
    
            [Column(TypeName = "nvarchar(50)")]
            [DisplayName("Spinnaker Sail Area: ")]
            public string SpinnakerSailArea { get; set; }
    
            [Column(TypeName = "nvarchar(50)")]
            [DisplayName("SA Optional ")]
            public string SAOptional { get; set; }
    
            [Column(TypeName = "nvarchar(50)")]
            [DisplayName("SA Optional 2")]
            public string SAOptional2 { get; set; }
    
            [Column(TypeName = "nvarchar(50)")]
            [DisplayName("Weight")]
            public string Weight { get; set; }
    
            [Column(TypeName = "nvarchar(50)")]
            [DisplayName("PYS")]
            public string PYS { get; set; }
    
            [Column(TypeName = "nvarchar(50)")]
            [DisplayName("Crew Persons")]
            public string CrewPersons { get; set; }
    
            [Column(TypeName = "nvarchar(50)")]
            [DisplayName("Crew Weight")]
            public string CrewWeight { get; set; }
    
            [Column(TypeName = "nvarchar(50)")]
            [DisplayName("Design By")]
            public string DesignBy { get; set; }
    
            [Column(TypeName = "nvarchar(50)")]
            [DisplayName("Design Year")]
            public string DesignYear { get; set; }
    
            [Column(TypeName = "nvarchar(50)")]
            [DisplayName("Olympic Boat")]
            public string OlympicBoat { get; set; }
    
            [Column(TypeName = "nvarchar(MAX)")]
            [DisplayName("Description")]
            public string Description { get; set; }
    
    
            [Column(TypeName = "nvarchar(50)")]
            [DisplayName("View in Olympic Section")]
            public string OlympicSectionViewSwitch { get; set; }
    
            [Column(TypeName = "nvarchar(50)")]
            [DisplayName("Image: ")]
            public string ImagePath { get; set; }

    public Manufacturers Manufacturers { get; set; } //This is where the manufacturers foreign key is being added to DB } }

    I have tried uploading snapshot of the error but I think this forum only allows pictures from URLs and not computers.

    Thursday, August 27, 2020 5:56 PM
  • User-474980206 posted

    Because you are using the view model as the entity model, you need to define the foreign key for manufactures.

    If the entity does not have a reference to manufactures, why the list.

    Thursday, August 27, 2020 8:20 PM
  • User1153554953 posted

    Entity has the reference to manufacturers, I have added Manufacturer object in the Dinghies.cs file, when I migrated the file and updated the database, it created Manufacturersid colum in the table at backend.

    I am not using any view model. I am very new to .net core, it would be more helpful if you tell me what change do I need to bring in the code? The interesting part, which I dont get the reason behind is, when I add and migrate this line in Dinghies.cs

    public Manufacturers Manufacturers { get; set; }

    It creates column "Manufacturersid" in the table and there is no column named "Manufacturers" but on the other hand when I try to access the data from database I can access "Manufacturers"(which is not available in table) and not "Manufacturersid"(which is available in the table)

    I have tried adding a separate column for ID, like:

            public int ManufacturerID { get; set; }
            public Manufacturers Manufacturers { get; set; }

    but when migrating, it creates two ID columns, one ManufacturerID and the other auto-created one by Manufacturers object, this confuses me that whats the need of 2 ID columns

    Friday, August 28, 2020 5:08 AM
  • User1153554953 posted

    UPDATE: I have tried adding additional column of ID named ManufacturerID in the table and tried setting ID to it through asp-items but it also didnt work out. asp-items was unable to set value to this column as well. The HTML page source of asp-items is as follows:

    <div class="form-group">
                <label class="control-label" for="Manufacturers">Manufacturers</label>
                <select class="form-control" id="Manufacturers" name="Manufacturers"><option value="1">hb</option>
    <option value="2">M1</option>
    <option value="3">M2</option>
    </select>
                <span class="field-validation-valid" data-valmsg-for="Manufacturers" data-valmsg-replace="true"></span>
                </div>

    So clearly asp-items is carrying values which its not transmitting to DB, one thing that I have noticed during debugging is that, either its Manufacturersid or the additional one ManufacturerID both are of "int" type whereas this value is of "string" type, can this cause some problem? This should have showed runtime error isnt it?

    Friday, August 28, 2020 5:45 AM
  • User-17257777 posted

    Hi najum98,

    Since you need receive the ManufacturerID, you should define it in the Dinghies class, and set it as the ForeignKey. And you should use            asp-for="ManufacturerID" in the select tag, so you can bind the Id value to ManufacturerID. Tested with the below codes:

    Model:

    public class Manufacturers
    {
        [Key]
        public int Id { get; set; }
        public string Name { get; set; }
        public string Address { get; set; }
    }
    
    public class Dinghies
    {
        public int Id { get; set; }
        public string Name { get; set; }
        [ForeignKey("Manufacturers")]
        public int ManufacturerID { get; set; }
        public Manufacturers Manufacturers { get; set; }
    }

    View:

    @model Dinghies
    @{
        ViewData["Title"] = "Home Page";
    }
    <form asp-action="AddDinghies" method="post">
        <div class="form-group">
            <label asp-for="Name" class="control-label"></label>
            <input class="form-control" asp-for="Name" />
            <span asp-validation-for="Name"></span>
        </div>
        <div class="form-group">
            <label asp-for="ManufacturerID" class="control-label"></label>
            <select class="form-control" asp-for="ManufacturerID" asp-items="ViewBag.Manufacturers"></select>
            <span asp-validation-for="ManufacturerID"></span>
        </div>
        <input type="submit" value="submit" class="btn btn-danger" />
    </form>

    Controller:

    public IActionResult Index()
    {
        var Manufacturers = _context.Manufacturers.ToList();
        List<SelectListItem> ListOfMan = new List<SelectListItem>();
        foreach (var manufacturer in Manufacturers)
        {
            ListOfMan.Add(new SelectListItem
            {
                Value = manufacturer.Id.ToString(),
                Text = manufacturer.Name //Name of manufacturer
            });
        }
        ViewBag.Manufacturers = ListOfMan;
        return View();
    }
    
    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> AddDinghies([Bind("Id,Name,ManufacturerID")] Dinghies dg)
    {
        if (ModelState.IsValid)
        {
            _context.Dinghies.Add(dg);
            await _context.SaveChangesAsync();
            return RedirectToAction(nameof(Index));
        }
        return View(dg);
    }

    Result:

    Best Regards,

    Jiadong Meng

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Friday, August 28, 2020 6:58 AM
  • User-821857111 posted

    A Dinghie can only have one manufacturer, so the navigation property should be a singular Manufacturer, not a collection of them. See how a book can only have one author in this example: https://www.learnentityframeworkcore.com/conventions/one-to-many-relationship#fully-defined-relationship

    The asp-for attribute is used to specify the property that you want the selected value to be bound to. The asp-items attribute specifies the items that appear in the select list: https://www.learnrazorpages.com/razor-pages/tag-helpers/select-tag-helper

    Friday, August 28, 2020 7:09 AM
  • User1153554953 posted

    Thank you for such a detailed response, jiadongm! I really appreciate your effort. I really felt for a moment that I found the solution to this problem but when I readded foreign key and navigation property to my Dinghies table as you mentioned above 

     [ForeignKey("Manufacturers")]
            public int ManufacturerID { get; set; }
            public Manufacturers Manufacturers { get; set; }

    It migrated successfully but while updating the database it failed and showed me this error

    The ALTER TABLE statement conflicted with the FOREIGN KEY constraint "FK_Dinghies_Manufacturers_ManufacturerID". The conflict occurred in database "CAdb", table "dbo.Manufacturers", column 'id'.

    and now the view page is also giving me some error 

    SqlException: Invalid column name 'ManufacturerID'.

    Even though there is no column name in database as update-database has not completed successfully.

    Friday, August 28, 2020 7:17 AM
  • User-17257777 posted

    Hi najum98,

    The ALTER TABLE statement conflicted with the FOREIGN KEY constraint "FK_Dinghies_Manufacturers_ManufacturerID". The conflict occurred in database "CAdb", table "dbo.Manufacturers", column 'id'.

    Is there any orignal data in your Dinghies table? If there is no important data in the table, I suggest you could first drop the table, do migration again, then update the database.

    Best Regards,

    Jiadong Meng

    Friday, August 28, 2020 8:15 AM
  • User1153554953 posted

    Is there any orignal data in your Dinghies table? If there is no important data in the table, I suggest you could first drop the table, do migration again, then update the database.

    Phew, at last some improvement as compared to previous situation, now data is being added to the tables perfectly, but now there is a new type of problem laughing I am able to add data through form and asp-items to tables but when I want to retrieve this data from table and want to get the name of the entity referenced by foreign key. It returns nothing.

    I have debugged it, and debugging shows that, "ManufacturersID" indeed contain an ID, but "Manufacturers" itself is null, why is it so? I established connection of foreign key (ManufacturersID) with navigation property("Manufacturers"), isn't it so?

    The syntax I used in .cshtml file for retrieving the name of the manufacturer is as follows:

                <td>
                    @Html.DisplayFor(modelItem => item.Manufacturers.Manufacturer)
                </td>

    Friday, August 28, 2020 11:04 AM
  • User1153554953 posted

     I am able to add data through form and asp-items to tables but when I want to retrieve this data from table and want to get the name of the entity referenced by foreign key. It returns nothing.

    I have debugged it, and debugging shows that, "ManufacturersID" indeed contain an ID, but "Manufacturers" itself is null, why is it so? I established connection of foreign key (ManufacturersID) with navigation property("Manufacturers"), isn't it so?

    Does anybody know a solution to this?

    Friday, August 28, 2020 6:34 PM
  • User1153554953 posted

    Hi najum98,

    Since you need receive the ManufacturerID, you should define it in the Dinghies class, and set it as the ForeignKey. And you should use            asp-for="ManufacturerID" in the select tag, so you can bind the Id value to ManufacturerID. Tested with the below codes:

    Hello there, I have marked your reply as answer as technically it solved the problem for which I created this thread, though I have some other issue which I would request you to check here 

    Though the issue of asp-items not posting data is solved but I have one question, why do we need to add Foreign Key above navigation property separately? As previously I just added the navigation property and EF Core added foreign key against it automatically, but I also dont get the fact that if EF Core added the foreign key for the navigation property itself than why couldn't I was able to access and set that foreign key like I can access the one I manually added. It's very confusing, I'll be glad if you can answer. Thanks for help though

    Saturday, August 29, 2020 5:59 AM