【问题标题】:Proper way to bind selectlistitems to viewmodel将选择列表项绑定到视图模型的正确方法
【发布时间】:2015-12-28 02:42:29
【问题描述】:

我已经多次看到此类问题被问到,但我无法找到正确且干净的方法来做到这一点。 在发布操作中,我的 PossibleAnswers 属性不再设置(正常,因为我没有将其发回)。由于数据来自数据库,我应该如何再次设置它?再次查询数据库对我来说似乎不合逻辑,尽管我猜它有效。是否有替代解决方案,例如缓存列表?

控制器

public ActionResult EditFirstCharac()
{
        var userId = _userService.GetUserIdFromName(_userName);
        var charac = _characService.GetAllUserCharacteristics(userId).ToList().FirstOrDefault(p => p.SelectedAnswer != null);

        var vm = new EditCharacViewModel()
        {
            CharacId = charac.Id,
            IsKey = charac.IsKey,
            Question = charac.Question.Title,
            Weight = charac.Weight,
            PossibleAnswers = charac.Question.PossibleAnswers.ToListSelectListItem(p => p.Id.ToString(), p => p.Label).ToList()
        };

        return View("Edit", vm);
    }

    [HttpPost]
    public ActionResult EditFirstCharac(EditCharacViewModel vm)
    {
        if (ModelState.IsValid)
        {
            // OK, save to DB or whatever
        }
        // KO, PossibleAnswers is empty
        return View("Edit", vm);
    }

视图模型

public class EditCharacViewModel
{
    public int CharacId { get; set; }
    public string Question { get; set; }

    [Range(0, 5)]
    public int Weight { get; set; }

    public bool IsKey { get; set; }
    public List<SelectListItem> PossibleAnswers { get; set; }
    public string SelectedAnswer { get; set; }
}

查看 @model Dating.WebSite.ViewModels.Profile.EditCharacViewModel

@using (Html.BeginForm("EditFirstCharac", "Profile"))
{
    <div>@Model.Question</div>

    @Html.EditorFor(p => p.IsKey)

    @Html.EditorFor(p => p.Weight)

    @Html.DropDownListFor(p => p.SelectedAnswer, Model.PossibleAnswers)

    @Html.HiddenFor(p => p.Question, new { id = "Question" })
    @Html.HiddenFor(p => p.CharacId, new { id = "CharacId" })
    <input type="submit" />
}

【问题讨论】:

  • 看来你已经有了答案。返回并再次从 DB 中获取列表是一种方法,尽管效率不高。这可能的答案是固定列表吗?我的意思是,它是否重视变化?如果没有,你可以像你说的那样使用缓存策略。
  • @jpgrassi 是的,这是一个固定列表。缓存听起来不错,但我不知道该怎么做。谢谢。
  • 你可以将它存储在应用程序上下文中,或者使用 .Net 4.0 MemoryCach(我已经使用过几次,效果很好)。看看这些链接:asp.net/web-forms/overview/data-access/caching-data/…; stevescodingblog.co.uk/net4-caching-with-mvc

标签: c# asp.net-mvc


【解决方案1】:

在发布操作中,不再设置我的 PossibleAnswers 属性 (正常,因为我不会发回)。

这是正确和预期的行为。 Http 是无状态的。 所以您的第二个请求(POST)不知道您在上一个请求(GET 请求)中对 PossibleAnswers 属性有什么了解

我应该如何重新设置它,因为数据来自数据库?查询 db 对我来说似乎又不合逻辑

是的。您需要重新加载数据。正如我之前提到的,Http 是无状态的,您当前的(POST)请求不会包含您在先前请求中加载的数据。在 ASP.NET Web 表单中,我们使用 ViewState 在请求之间保持数据。那更像是一个黑客。下拉列表的内容被加密为字符串并存储在隐藏字段中并回发到服务器。发回后,服务器将解密字符串并再次加载下拉列表。这种 hack/trick 通常违反 Http 的概念,其中一个请求不应该对先前的请求有任何想法。

所以你应该做的是

[HttpPost]
public ActionResult EditFirstCharac(EditCharacViewModel vm)
{
    if (ModelState.IsValid)
    {
        // OK, save to DB or whatever and Redirect to a GET action (PRG pattern)
    }
    //Reload data
    vm.PossibleAnswers = charac.Question.PossibleAnswers
                        .ToListSelectListItem(p => p.Id.ToString(), p => p.Label).ToList();
    return View("Edit", vm);
}

【讨论】:

  • 感谢您的回答。您是否同意缓存也是不再查询数据库的好解决方案? (我知道这与您提供的答案无关,只是询问)。再次感谢
  • 当然。像这样的缓存数据通常不会更改)。所有查找数据都是很好的缓存候选者。这是一个示例stackoverflow.com/questions/33402051/…,这是一个用于MVC6的示例stackoverflow.com/questions/34414310/…
  • 非常感谢这些非常有用的链接。
猜你喜欢
  • 2011-08-10
  • 1970-01-01
  • 1970-01-01
  • 2013-04-05
  • 1970-01-01
  • 1970-01-01
  • 2013-04-28
  • 1970-01-01
  • 2015-08-27
相关资源
最近更新 更多