使用Lambda或Linq为MVC5中的razor View创建具有Selected项的SelectList模型

rwk*_*iii 9 c# linq asp.net-mvc razor asp.net-mvc-4

我首先使用EF代码,使用MVC5 C#作为我的Web应用程序.我创建了一个db表,其中包含几十个设置的主定义,这些设置用于在整个应用程序中指定输入和输出参数.

我还创建了一个用户ID密钥表.创建的每个用户都将获得默认设置,可以使用"用户首选项"(剃刀)"查看"页面随时更改这些设置.

现在我正在尝试为此View页面编写控制器操作.大多数所有这些用户首选项都需要从下拉列表中进行选择,但这对我来说很困惑.

// UOM Master Table
public class UOMMaster
{
    public int Id { get; set; }
    public string MeasureId { get; set; }         // Text used as labels
    public double SortOrder { get; set; }         // User preferences sort order
    public string UOMId { get; set; }             // UOM abbreviation
    public bool IsUserPreference { get; set; }    // true if is a stored user preference
}
Run Code Online (Sandbox Code Playgroud)

上面的主表数据可能如下所示:

1,   "AbsolutePress",   1,   "psi",    true
2,   "AbsolutePress",   1,   "kPaa",   true
3,   "FluidFlow",       2,   "GPM",    true
4,   "FluidFlow",       2,   "m^3/Hr", true
5,   "FluidFlow",       2,   "l/s",    true

etc, etc...
Run Code Online (Sandbox Code Playgroud)

包含ICollection的自定义标识:

public class ApplicationUser : IdentityUser
{
    // Default Units of Measure
    public virtual ICollection<AspNetUserUOMDefault> UOMDefaults { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

首选用户默认值存储在Identity的UserId上的表中:

public class AspNetUserUOMDefault
{
    [Key]
    public virtual ApplicationUser UserProfile { get; set; }

    public int Id { get; set; }
    public string MeasureId { get; set; }
    public string PreferredUomId { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

使用上面的表格,我需要创建一个剃刀视图,显示下拉列表以显示用户的首选设置:

                  +--------------+---+
AbsolutePress:    | psi          | V |     <-- Dropdown list containing 
                  +--------------+---+         all options available for
                  | psi              |         AbsolutePress as defined in
                  | kPaa             |         master table, with user's
                  +------------------+         preferred setting selected.

FluidFlow:        +--------------+---+
                  | m^3/Hr       | V |     <-- Dropdown list containing
                  +--------------+---+         all options available for
                  | GPM              |         FluidFlow as defined in
                  | m^3/Hr           |         master table, with user's
                  | l/s              |         preferred setting selected.
                  +------------------+

etc, etc...
Run Code Online (Sandbox Code Playgroud)

GET控制器行动让我感到困惑.我只是不知道如何将模型返回到剃刀View,但它需要由SortOrder(升序)排序并包含一个包含以下内容的SelectList(也许是??)的IList/ICollection(我'我不知道该怎么做):

UOMPreferences
    MeasureId
    optionsList
        UomId
        UomId (Selected)
        UomId
UOMPreferences
    MeasureId
    optionsList
        UomId (Selected)
        UomId

   etc, etc..
Run Code Online (Sandbox Code Playgroud)

View模板需要使用SortOrder顺序中的下拉列表显示Model的内容.我设想这是动态的,这样可以将首选项添加到数据库表中,而无需对Controller Actions或razor View模板进行任何更改.

在视图中会有一个foreach(我不知道该怎么做):

@foreach (var preference in Model.UOMPreferences)
{
<div class="form-group">
    @Html.LabelFor(preference.MeasureId, new { @class = "col-md-3 control-label" })
    <div class="col-md-4">
        @Html.DropDownListFor(
            preference.MeasureId,
            new SelectList(preference.optionsList, "Value", "Text"), 
            new { @class = "form-control" })
    </div>
</div>
}
Run Code Online (Sandbox Code Playgroud)

有没有人有经验和时间向我提供有关如何实现此目的的代码段建议?可能我最大的困惑在于Controller Actions本身(GET和POST).我真的不在乎模型是用Lambda还是Linq创建的,但我无法想象如何做到这一点 - 我相信它可以.我的数据库模型可能会有所改进,但我认为它们会起作用吗?

小智 1

根据您的补充意见,我建议采用不同的结构。

首先是数据库表

AbsolutePressOptions: ID(PK), Name, IsDefault(bit)
FluidFlowOptions: ID(PK), Name(varchar), IsDefault(bit)
//more tables for other options types
UserOptions: UserID(PK), AbsolutePressPreference(FK), FluidFlowPreference(FK), etc
Run Code Online (Sandbox Code Playgroud)

由于每个选项类型的值不太可能更改,因此您还可以考虑使用枚举而不是创建数据库表,例如

public enum AbsolutePressOption
{
  psi,
  kpa
}
Run Code Online (Sandbox Code Playgroud)

用户选项类(基于使用枚举)

public class UserOptions
{
  public UserOptions()
  {
    // Set defaults
    AbsolutePressPreference = AbsolutePressOption.psi;
  }
  public AbsolutePressOption AbsolutePressPreference { get; set; }
  public FluidFlowOption FluidFlowPreference { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

用户

public class User
{
  public User()
  {
    // Assign default options when user initialised
    Options = new UserOptions();
  }
  .... // properties of user (ID, Name etc.)
  public UserOptions Options { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

如果用户采用默认值,则无需将任何内容保存到数据库中。要更改他们的选项,您的控制器可能类似于

[HttpGet]
public ActionResult UserOptions(int ID)
{
  User user = UserRepository.Get(ID); // get user and user options from database

  ViewBag.AbsolutePressOptions = new SelectList(....
  return View(user);
}
Run Code Online (Sandbox Code Playgroud)

请注意,要从 MVC-4 的枚举创建 SelectList,请参阅此处。另外,最好创建一个包含 SelectList 属性的 ViewModel。

风景

@model YourAssembly.User
// Some display properties of the user (Name etc.)
....
@using (Html.BeginForm())
{
  @Html.HiddenFor(m => m.ID) // so the user ID posts back
  @Html.LabelFor(m => m.Options.AbsolutePressPreference)
  @Html.DropDownFor(m => m.Options.AbsolutePressPreference, (SelectList)ViewBag.AbsolutePressOptions)
  // More selects for other options
  <input type="submit" value="Save Options" />
}
Run Code Online (Sandbox Code Playgroud)

以及post方法

[HttpGet]
public ActionResult UserOptions(User user)
{
  if (!ModelState.IsValid)
  {
    // Build select lists again
    return View(user)
  }
  UserRepository.SaveOptions(user) // Save options to database
  // Redirect to the user details page?
  return RedirectToAction("Details", new { ID = user.ID })
}
Run Code Online (Sandbox Code Playgroud)

最后,如果在大多数页面上使用用户首选项,我会考虑创建一个CustomPrincipal将用户首选项写入FormsAuthenticationTicketcookie 的cookie,以便其在每个请求中可用。