0

I am trying to save my dropdown list values to my database in an ASP.NET web application using MVC6 and Entity Framework 7 but the values are not saving.

I have two classes one called expenses and when a user creates an expense they need to select a country. I have the country dropdown list populating but when the expense is saved the countryid is not being saved to the database.

Models

public class Country
{        public int Countryid { get; set; }
        public string CountryCode { get; set; }
}

public class Expense
{
    public int ExpenseId { get; set; }

    [DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}",
    ApplyFormatInEditMode = true)]
    public DateTime ExpenseDate { get; set; }
    public virtual Country Countryid { get; set; }

Expense Controller

 private void PopulateCountriesDropDownList(object selectedCountry = null)
    {
        var list = _context.Countries.OrderBy(r => r.CountryCode).ToList().Select(rr =>

        new SelectListItem { Value = rr.Countryid.ToString(), Text = rr.CountryCode }).ToList();
        ViewBag.Countries = list;
    }
    // GET: Expenses/Create
    public IActionResult Create()
    {
        PopulateCountriesDropDownList();
                   return View();
    }

    // POST: Expenses/Create
    [HttpPost]
    [ValidateAntiForgeryToken]
    public IActionResult Create(Expense expense)
    {
        if (ModelState.IsValid)
        {
            _context.Expenses.Add(expense);
            _context.SaveChanges();
            return RedirectToAction("Index");
        }
        PopulateCountriesDropDownList(expense.Countryid);

        return View(expense);
    }

View

 <div class="form-group">
        <label asp-for="Countryid" class="col-md-2 control-label"></label>
        <div class="col-md-10">
            <select asp-for="Countryid" class="form-control"[email protected]></select>
            <span asp-validation-for="Countryid" class="text-danger" />
        </div>
    </div>

1 Answer 1

1

First of all the Countryid property in your Expense model is a of a complex type (Country). The model binder cannot map the posted Countryid form value to this Complex object.

You should add a CountryId property to your Expense model of type Int

public class Expense
{
    public int ExpenseId { get; set; }

    [DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}",
    ApplyFormatInEditMode = true)]
    public DateTime ExpenseDate { get; set; }
    public int CountryId { set;get;}
    public virtual Country Country { get; set; }    
}

While this will fix the problem, A more better & clean solution is to use a view model for transferring data between your view and action method. With this approach your view is not tightly coupled to the entity classes generated by your ORM.

So create a view model for your view with properties absolutely needed for the view.

public class CreateExpenseVm
{
   public List<SelectListItem> Countries { set;get;}
   public int CountryId { set;get;}
   //Add other properties, if your view need them.
}

and in your GET action, you create an object of this class, load the Countries collection property and send it to your view.

public ActionResult Create()
{
   var vm=new CreateExpenseVm();
   vm.Countries = _context.Countries.OrderBy(r => r.CountryCode)
                       .Select(x=>new SelectListItem { Value=x.CountryId.ToString(),
                                                       Text=x.CountryCode}).ToList();
   return View(vm);
}

And in your view,which is strongly typed to our new viewmodel,

@model CreateExpenseVm
<form asp-controller="Expense" asp-action="Create">      
    <label>Select Country</label>
    <select asp-for="CountryId" asp-items="@Model.Countries" >
        <option>Please select one</option>
    </select>
    <input type="submit"/>
</form>

and in your HttpPost action, Use CreateExpenseVm as the parameter type. When the form is submitted, the default model binder will be able to map the posted form data to the properties of this class object.

[HttpPost]
public ActionResult Create(CreateExpenseVm model)
{
   var e=new Expense { CountryId=model.CountryId };
   e.ExpenseDate = DateTime.Now;
   dbContext.Expenses.Add(e);
   dbContext.SaveChanges();
   return RedirectToAction("Index");
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.