当数据库值为NULL时,在下拉列表中添加空选项

本文关键字:下拉列表 添加 选项 数据库 NULL | 更新日期: 2023-09-27 18:05:13

我有一个数据库表,有几个外键字段。当我加载一个记录进行编辑时,有下拉列表,在Razor中使用@Html.DropDownList创建,它正确地显示了外键列引用的表中的可能值。而且,因为我正在编辑一条记录,如果一个值之前已经从外键表中被选中,那么它的ID就在主表的外键列中,正如您所期望的那样。

但是,如果我加载编辑的记录在一个外键列中没有值-即,列中的值为NULL(并且它们都是可空的,原因超出了我的控制),默认情况下,下拉菜单选择了第一个选项。这不仅会产生误导,因为没有办法知道这个选项被显示是因为它以前被保存过,还是因为它只是第一个选项,这还意味着当我随后保存记录时,第一个选项的值被错误地保存到数据库中。

我需要的是每个下拉列表还包括一个"未知"选项,动态添加(即不在数据库中),这是选择当页面加载时,如果基础外键列有一个NULL值,这可以由用户选择,如果他们想改变以前保存的值为NULL。

当页面加载时,我使用jQuery给下拉列表添加一个值没有问题,像这样:

$("select").prepend("<option value=''>Unknown</option>")

但是,当页面加载时,即使这个新选项作为列表中的第一个选项成功添加,它也没有被选中。第一个"真正的"选择是。而且,即使我可以使用jQuery强制选择'dummy'选项,也会在数据库中存在真实值的下拉框中选择dummy选项。

这真的不像是什么不寻常或晦涩的事情,但我在谷歌上搜索了一个下午后,一直在努力寻找任何解决方案。我尝试了各种各样的东西,从堆栈溢出,我认为我可能能够使工作,但无济于事。

谁能提出解决方案?我认为在控制器中添加一个"虚拟"选项可能是最简洁的方法,如果我能找到方法的话。我很惊讶这不是一个很常见的问题!

加载下拉列表值的控制器代码如下:

ViewBag.PremisesID = new SelectList(db.Premises, "ID", "StreetName", colicCase.PremisesID);

下拉菜单对应的Razor如下所示:

<div class="form-group">
     @Html.LabelFor(model => model.PremisesID, htmlAttributes: new { @class = "control-label col-md-4" })
     <div class="col-md-8">
         @Html.DropDownList("PremisesID", null, htmlAttributes: new { @class = "form-control" })
         @Html.ValidationMessageFor(model => model.PremisesID, "", new { @class = "text-danger" })
    </div>
</div>

当数据库值为NULL时,在下拉列表中添加空选项

该功能已经通过使用DropDownList()DropDownListFor()方法的重载之一内置到MVC中,该方法接受optionLabel参数,例如

public static MvcHtmlString DropDownList(
    this HtmlHelper htmlHelper,
    string name,
    IEnumerable<SelectListItem> selectList,
    string optionLabel,
    object htmlAttributes
)

或强类型版本

public static MvcHtmlString DropDownListFor<TModel, TProperty>(
    this HtmlHelper<TModel> htmlHelper,
    Expression<Func<TModel, TProperty>> expression,
    IEnumerable<SelectListItem> selectList,
    string optionLabel,
    object htmlAttributes
)

,其中optionLabel的值将被添加为null值的第一个选项(生成例如<option value="">Unknown</option>)。

我强烈建议您使用强类型版本,并且您使用带有SelectList属性的视图模型,而不是使用ViewBag,但在任何情况下,不要为您绑定到的属性和ViewBag属性使用相同的名称(有关更多细节,请参阅此回答)

你的代码应该是
public class MyViewModel
{
    ....
    public int? PremisesID { get; set; }
    public IEnumerable<SelectListItem> PremisesList { get; set; }
    ....
}

和GET方法

var model = new MyViewModel()
{
    .... // map properties from the data model
    PremisesID = dataModel.PremisesID,
    PremisesList = new SelectList(db.Premises, "ID", "StreetName")
};
return View(model);

和视图

@Html.DropDownListFor(m => m.PremisesID, Model.PremisesList, "Unknown", new { @class = "form-control" })

如果PremisesID的值是null或者与Premises表中的ID的值不匹配,则选择第一个选项