Asp.net MVC ModelState.Isvalid为Id返回false

时间:2017-09-08 04:53:10

标签: asp.net-mvc model modelstate

我正在看这个ASP.NET MVC course。我有一个customer model,其中包含以下属性。

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; }
}

请注意,Id没有Required数据注释。但是在我的数据库中,Id是主键,而该列的标识是真的。

ViewModelCustomerMembershipType模型。

    public class CustomerFormViewModel {
        public IEnumerable<MembershipType> MembershipTypes { get; set; }
        public Customer Customer { get; set; }
    }

我有一个使用new CustomerNameDateOfBirthMembershipType字段创建IsSubscribedToNewsLetter的视图。需要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>
}

这是我的Save控制器:

    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");
    }

当我填写CustomerForm视图并单击提交按钮时,ModelState.Isvalid()方法始终为false;导致if statement方法的第一个Save为true。所以我不能存储任何新客户。

我尝试debugbreakpoint放在if (!ModelState.IsValid)上,然后看到Id字段正在创建错误(说“需要Id字段”) 。为什么说Id不是必需的? ModelState.IsValid方法是否在数据库级别检查模型?我不这么认为。

如果我像这样更改Customer模型的Id属性:public int? Id { get; set; }并更改if语句,if ((!ModelState.IsValid) && (customer.Id==null) )应用程序正常工作。

这个Id问题还有其他解决办法吗?

9 个答案:

答案 0 :(得分:1)

我看了同样的课程,我猜你的作者自从看了之后就更新了,因为他展示了这个确切的问题类型。问题是当将View Model返回到New Action上的View时,Customer属性未初始化,因此Id为null,因此在尝试保存时ModelState失败

只需更改如下,以便在设置viewModel时初始化Customer,然后Id为0:

 public ActionResult New()
    {
        var memberShipTypes = _context.MembershipTypes.ToList();

        var viewModel = new CustomerViewModel
        {
            Customer = new Customer(),
            MembershipTypes = memberShipTypes
        };

        return View("CustomerForm", viewModel);
    }

答案 1 :(得分:1)

对此花了很长时间,并创建了一种解决方法,但是看来Mosh在稍后的部分中将其设置为“电影格式”。

https://codewithmosh.com/courses/222293/lectures/3684111

简短的答案是将@Html.Hidden("Movie.Id", (Model.Movie != null) ? Model.Movie.Id : 0)添加到MovieForm.cshtml。

然后,他描述了一种避免将“ Movie.Id”硬编码到视图中的方法(请参见https://github.com/mosh-hamedani/vidly-mvc-5/commit/e5b994581931a079ad87418ddcf9338e808bd821#diff-e94a8dc96403203b00e58238bb80101c

答案 2 :(得分:0)

问题可能是Id字段标记为int而非int?。将变量设置为int模型会自动假定该属性的值将被标记为nullable

尝试将Id属性标记为int?并查看结果是否符合您的预期。

答案 3 :(得分:0)

这只是草稿,因为我现在无法访问VS.无论如何,修改你的保存操作,如下所示:

public ActionResult Save(CustomerFormViewModel customerVM) {
    if (!ModelState.IsValid) {
        return View(customerVM);
    }
    if (customer.Id == 0) {
        _context.Customers.Add(customerVM.Customer);
    }
    else {
        var CustomerInDb = _context.Customers.Find(customerVM.Customer.Id);
        CustomerInDb.Name = customer.Name;
        CustomerInDb.DateOfBirth = customer.DateOfBirth;
        CustomerInDb.IsSubscribedToNewsLetter = customer.IsSubscribedToNewsLetter;
        CustomerInDb.MembershipTypeId = customer.MembershipTypeId;
    }
    _context.SaveChanges();
    return RedirectToAction("Index", "Customer");
}

哦,您可以从视图中删除以下内容,因为这是用于创建页面:

    @Html.HiddenFor(m=>m.Customer.Id)

答案 4 :(得分:0)

他们在模型类中将Id更改为CustomerId。 我认为只是&#39; Id&#39;可以被视为该模型类的主键。

答案 5 :(得分:0)

我们正在做相同的课程,我遇到了完全相同的问题大声笑。 在我看来,我找到了一个非常好的解决方法。

只需在CustomerFormView中添加这些代码行即可。 代替 @Html.HiddenFor(m=>m.Customer.Id)

添加:

 {
        if (Model.Customer == null)
        {
            <input data-val="true" data-val-number="The field Id must be a number." data-val-required="The Id field is required." id="Customer_Id" name="Customer.Id" type="hidden" value="0" />
        }
        else
        {
            @Html.HiddenFor(m => m.Customer.Id)
        }
    }

由于某种原因,我看到当我尝试添加新客户时,id的值是空字符串而不是零。 因此,如果Customer对象为null,我会手动将其更改为零 (添加新客户时总会如此。) 它对我来说很好。

如果您认为此解决方案存在问题,请与我们联系。

BTW关于你的问题:&#34; Id字段正在创建错误(说&#34; Id字段是必需的&#34;)。为什么说它不是必需的时候是必需的?&#34;

Int数据类型是不可为空的,因此它是隐式需要的......作为MembershipId(没有[Required]注释的字节数据类型。)

答案 6 :(得分:0)

我也正在学习这门课程。我有同样的问题。在customerviewform中添加此行

if (Model.Customers !=null)
    {
        @Html.HiddenFor(m => m.Customers.Id)
    }

为什么我要添加,因为虽然隐藏它用于编辑目的,如果你删除它也将是问题。那么添加这一行我们将工作并在客户模型中添加public int? Membershiptype。如果你在下拉列表中遇到错误,那么在添加新客户的同时,在验证区域返回之前添加此行

 customer.MembershipTypes = _Context.MembershipTypeTableset.ToList(); add this line before     View("CustomerForm", viewModel)

答案 7 :(得分:0)

此示例摘自Mosh Hamedani的MVC 5课程。他在第55章中解释了客户ID问题。可以通过在创建CustomerFormViewModel时在New方法中传递新的customer()对象来解决此问题。

答案 8 :(得分:-1)

在看到this问题之后,我解决了我的问题。我刚刚在Id操作开始时在ModelState中停用了Save个错误。

public ActionResult Save(Customer customer) {
    ModelState["customer.Id"].Errors.Clear();
    if ((!ModelState.IsValid) ) {
        var viewModel = new CustomerFormViewModel {
            Customer = customer,
            MembershipTypes = _context.MembershipTypes.ToList()
        };
        return View("CustomerForm", viewModel);
    }
    if (customer.Id == 0) {
        _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");
}

现在我的应用程序工作正常。

相关问题