I'm watching this ASP.NET MVC course. I have a customer
model
with these following attribute.
public class Customer {
public int Id { get; set; }
[Required]
[StringLength(255)]
public string Name { get; set; }
[Display(Name = "Date of Birth")]
public DateTime? DateOfBirth { get; set; }
public bool IsSubscribedToNewsLetter { get; set; }
public MembershipType MembershipType { get; set; }
[Display(Name="Membership Type")]
public byte? MembershipTypeId { get; set; }
}
Note thate the Id has no Required
data annotation. But in my database, the Id is primary key and Identity is true for the column.
There is a ViewModel
consisting Customer
and MembershipType
models.
public class CustomerFormViewModel {
public IEnumerable<MembershipType> MembershipTypes { get; set; }
public Customer Customer { get; set; }
}
I have a View that creates new Customer
with Name
, DateOfBirth
, MembershipType
and IsSubscribedToNewsLetter
fields. It takes the CustomerFormViewModel
.
@using Vidly.Models
@model Vidly.ViewModel.CustomerFormViewModel
@{
ViewBag.Title = "New";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>@ViewBag.Message</h2>
@using (Html.BeginForm("Save", "Customer")) {
<div class="form-group">
@Html.LabelFor(m => m.Customer.Name,new{@class="control-label"})
@Html.TextBoxFor(m => m.Customer.Name, new { @class = "form-control" })
@Html.ValidationMessageFor(m=>m.Customer.Name)
</div>
<div class="form-group">
@Html.LabelFor(m => m.Customer.DateOfBirth, new { @class = "control-label"})
@Html.TextBoxFor(m => m.Customer.DateOfBirth,"{0:d MMM yyyy}", new { @class = "form-control" })
</div>
<div class="form-group">
@Html.LabelFor(m => m.Customer.MembershipTypeId, new { @class = "control-label"})
@Html.DropDownListFor(m => m.Customer.MembershipTypeId,new SelectList(Model.MembershipTypes,"Id","Name"), "Select Membership Type", new { @class = "form-control" })
</div>
<div class="checkbox">
<label>
@Html.CheckBoxFor(m => m.Customer.IsSubscribedToNewsLetter) Subscribed To Newsletter?
</label>
</div>
@Html.HiddenFor(m=>m.Customer.Id)
<button type="submit" class="btn btn-primary">Save</button>
}
Here is my Save
controller:
public ActionResult Save(Customer customer) {
if (!ModelState.IsValid) {
var viewModel = new CustomerFormViewModel {
Customer = customer,
MembershipTypes = _context.MembershipTypes.ToList()
};
return View("CustomerForm", viewModel);
}
if (customer.Id == 0 || customer.Id==null) {
_context.Customers.Add(customer);
}
else {
var CustomerInDb = _context.Customers.Single(c => c.Id == customer.Id);
CustomerInDb.Name = customer.Name;
CustomerInDb.DateOfBirth = customer.DateOfBirth;
CustomerInDb.IsSubscribedToNewsLetter = customer.IsSubscribedToNewsLetter;
CustomerInDb.MembershipTypeId = customer.MembershipTypeId;
}
_context.SaveChanges();
return RedirectToAction("Index", "Customer");
}
When I fill the CustomerForm
view and click the submit button, the ModelState.Isvalid()
method always comes false; resulting the first if statement
of the Save
method true. So I can't store any new customer.
I tried to debug
the application by putting breakpoint
on if (!ModelState.IsValid)
and saw that the Id
field is creating a error(saying "The Id field is required"). Why is it saying that Id
is required when it isn't? Does the ModelState.IsValid
method check the model at database level? I don't think so.
If I change the Customer
model's Id
property like this:public int? Id { get; set; }
and change the if statement by this,if ((!ModelState.IsValid) && (customer.Id==null) )
the application works fine.
Is there any other solution of this Id
problem?
Perhaps the problem is that the
Id
field is marked as anint
and notint?
. Putting a variable asint
the Model automatically assumes there's going to be a value for this property since it's not markednullable
.Try marking the
Id
Property isint?
and see if the results are what you expect or not.