【问题标题】:Not Allowing Nullable Dropdown Field on Create不允许在创建时为空下拉字段
【发布时间】:2018-03-23 23:42:17
【问题描述】:

我正在使用实体框架来创建我的模型,并且我有一些字段是外键但也可以为空。例如,设备的状态可能未知,所以如果是这种情况,我将其设置为 NULL。如果设备确实有状态,则值为 Dev_Status_ID,它引用 Device_Status 表,因此 Dev_Status_Name 可以显示在网站上。

我一直在测试以确保正确处理创建和编辑期间的空字段,但事实并非如此。当我将设备状态下拉列表保留在默认 String.Empty 值上时,当我单击提交按钮时,网站会突出显示设备状态下拉列表。

设备创建视图:

@model ITInventory.Models.Device
@{
    ViewBag.Title = "Create";
}
<h2>Create</h2>

@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()
<div class="form-horizontal">

    <h4>Device</h4>

    <hr />
    @Html.ValidationSummary(true, "", new { @class = "text-danger" })
            @* Asset Tag *@
            <div class="form-group">
                @Html.LabelFor(model => model.dev_asset_tag, htmlAttributes: new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @Html.EditorFor(model => model.dev_asset_tag, new { htmlAttributes = new { @class = "form-control" } })
                    @Html.ValidationMessageFor(model => model.dev_asset_tag, "", new { @class = "text-danger" })
                </div>
            </div>

            @*......Leaving out a bunch of other fields for readability*@

            @*Status*@
            <div class="form-group">
                @Html.LabelFor(model => model.Device_Status.dev_status_name, htmlAttributes: new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @Html.DropDownListFor(m => m.Device_Status.dev_status_id, (SelectList)ViewBag.dev_status_id, String.Empty, new { @class = "form-control" })
                    @Html.ValidationMessageFor(model => model.dev_status_id, "", new { @class = "text-danger" })
                </div>
            </div>

            @*.......Leaving out a bunch of other fields for readability*@

            <div class="form-group">
                <div class="col-md-offset-2 col-md-10">
                    <input type="submit" value="Create" class="btn btn-default" />&nbsp;&nbsp;&nbsp;&nbsp;
                    <input type="reset" value="Cancel" class="btn btn-default" />
                </div>

            </div>
        </div>
}
<div>
    @Html.ActionLink("Back to List", "Index")
</div>

设备型号:

namespace ITInventory.Models
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.ComponentModel.DataAnnotations;
    using System.Web.Mvc;

    public partial class Device
    {
    
        [DisplayName("Device ID")]
        public int dev_id { get; set; }

        [DisplayName("Asset Tag")]
        public string dev_asset_tag { get; set; }

        @*.......Leaving out a bunch of other fields for readability*@

        [DisplayName("Status ID")]
        public Nullable<int> dev_status_id { get; set; }

        @*.......Leaving out a bunch of other fields for readability*@
       
        public virtual Device_Status Device_Status { get; set; }
        @*.......Leaving out the other public virtual bits for readability*@*@
    }
}

状态模型:

namespace ITInventory.Models
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.ComponentModel.DataAnnotations;
    using System.Web.Mvc;

    public partial class Device_Status
    {
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
        public Device_Status()
        {
            this.Devices = new HashSet<Device>();
        }

        [DisplayName("Status ID")]
        public int dev_status_id { get; set; }

        [DisplayName("Status")]
        public string dev_status_name { get; set; }
    
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
        public virtual ICollection<Device> Devices { get; set; }
    }
}

设备控制器:

// GET: Devices/Create
        public ActionResult Create()
        {
            @*.......Leaving out a bunch of other fields for readability*@
            
            ViewBag.dev_status_id = new SelectList(db.Device_Status.OrderBy(x => x.dev_status_name), 
            "dev_status_id", "dev_status_name");
            
            @*.......Leaving out a bunch of other fields for readability*@
            return View();
        }

        // POST: Devices/Create
        // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
        // more details see https://go.microsoft.com/fwlink/?LinkId=317598.
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Create(Device device)
        {
            if (ModelState.IsValid)
            {
                db.Devices.Add(device);
                db.SaveChanges();
                return RedirectToAction("Index");
            }

            @*.......Leaving out a bunch of other fields for readability*@
            
            ViewBag.dev_status_id = new SelectList(db.Device_Status, "dev_status_id", "dev_status_name", null);
            
            @*.......Leaving out a bunch of other fields for readability*@
            
            return View(device);
            }

我是 MVC 的新手,所以我觉得我一定遗漏了一些明显的东西,但是我的所有搜索都没有帮助。我的字段设置为 Nullable,我没有字段Required,当我尝试手动对数据库执行插入操作时,它不会抱怨 NULL dev_status_id。我是否试图做一些不允许的事情?

【问题讨论】:

  • 首先,您有一个Device_Status.dev_status_name 属性的标签(并且没有关联的控件,因此它不是标签)然后您将下拉列表绑定到属性Device_Status.dev_status_id,,但对dev_status_id 进行了关联验证(他们是不一样的)。删除所有这些糟糕的代码。您正在编辑数据,因此请始终使用视图模型 - What is ViewModel in MVC?。您的视图模型将包含属性int? SelectedStatusIEnumerable&lt;SelectListItem&gt; StatusList
  • 然后参考this Q/A了解如何正确编码
  • 并且突出显示下拉列表的原因是您绑定到 int(您的 Device_Status.dev_status_id 属性)和 int 必须有一个值 - 它不能是 null 这是第一个选项的价值。但是您永远不会看到相关的错误消息,因为您为完全不同的属性创建了验证消息。

标签: c# asp.net-mvc validation


【解决方案1】:

在这种情况下,您应该有 2 个模型。

一个是服务模型,您使用 Nullable,可能会存储一些数据以供以后决策。将它与您的所有逻辑一起使用。

另一种是 ViewModel(例如 DeviceViewModel),您只放置将显示的有效数据。这个模型应该是轻量级的,并且 100% 对显示规则有效。

因此,当您完成控制器中的所有逻辑后,您可以从服务模型中组合 ViewModel 并显示它。

【讨论】:

  • 谢谢,我现在正在尝试。
  • 使用 ViewModel 让一切变得如此简单。谢谢!
【解决方案2】:

可能是当您选择默认值时,在服务器端它可能是空字符串,请在后期操作中检查它。如果它的空字符串将 DBNull.Value 分配给 dev_status_id

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-10-04
    • 1970-01-01
    • 1970-01-01
    • 2020-02-07
    • 2013-08-22
    • 2010-11-03
    • 1970-01-01
    相关资源
    最近更新 更多