C# 使用Lambda或Linq为MVC5中的razor视图创建带有选定项的SelectList模型

C# 使用Lambda或Linq为MVC5中的razor视图创建带有选定项的SelectList模型,c#,asp.net-mvc,linq,asp.net-mvc-4,razor,C#,Asp.net Mvc,Linq,Asp.net Mvc 4,Razor,我在我的web应用程序中首先使用EF代码和MVC5 C。我创建了一个db表,其中包含几十个设置的主定义,这些设置用于在整个应用程序中指定输入和输出参数 我还创建了一个在用户ID上设置键的表。创建的每个用户都有默认设置,可以随时使用用户首选项(razor)查看页面进行更改 现在,我正在尝试为此视图页面编写控制器操作代码。大多数用户偏好都需要从下拉列表中进行选择,但这让我感到困惑 // UOM Master Table public class UOMMaster { public int

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

我还创建了一个在用户ID上设置键的表。创建的每个用户都有默认设置,可以随时使用用户首选项(razor)查看页面进行更改

现在,我正在尝试为此视图页面编写控制器操作代码。大多数用户偏好都需要从下拉列表中进行选择,但这让我感到困惑

// 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
}
上面的主表数据可能如下所示:

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...
具有包含以下内容的ICollection的自定义标识:

public class ApplicationUser : IdentityUser
{
    // Default Units of Measure
    public virtual ICollection<AspNetUserUOMDefault> UOMDefaults { get; set; }
}
使用上表,我需要创建一个razor视图,该视图显示下拉列表,以显示用户的首选设置:

                  +--------------+---+
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...
视图模板需要使用下拉列表按排序顺序显示模型的内容。我设想这是动态的,这样就可以将首选项添加到数据库表中,而无需对控制器操作或razor视图模板进行任何更改

在视图中,将有一个foreach(我不知道如何做到这一点):

@foreach(Model.UOMPreferences中的变量首选项)
{
@LabelFor(preference.MeasureId,新的{@class=“col-md-3控制标签”})
@Html.DropDownListFor(
preference.MeasureId,
新建选择列表(preference.options列表,“值”、“文本”),
新的{@class=“表单控制”})
}

有没有人有经验和时间为我提供关于如何完成这一任务的代码片段建议?可能我最大的困惑是控制器动作本身(GET和POST)。我真的不在乎模型是用Lambda还是Linq创建的,但我只是无法想象如何做到这一点——我相信这是可以做到的。我的数据库模型可能会得到改进,尽管我认为它们会起作用。

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

首先是数据库表

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
<> P>因为每个选项类型的值不太可能改变,所以您也可以考虑使用枚举而不是创建数据库表,例如

public enum AbsolutePressOption
{
  psi,
  kpa
}
用户选项类(基于使用枚举)

使用者

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

[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);
}
注意,要从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" />
}

最后,如果在大多数页面上使用了用户首选项,我会考虑创建一个<代码>客户主体< /> >,将用户首选项写入FuxSouthTyCuffsCookie,因此它在每个请求中都是可用的。

在您的视图

中应该是这样的。
@foreach (string preference in Model.UOMPreferences.OrderBy(p=>p.SortOrder)
                                                .Select(p=>p.MeasureId )
                                                .Distinct())
{
    var preferences = Model.UOMPreferences.Where(p=>p.MeasureId = preference);
....
     @Html.DropDown(preference, new SelectList(preferences, "Id", "UOMId"))
....
}

我不确定我是否完全理解了这个问题,但我发现MVC下拉列表的最佳方法是在包含下拉列表所有选项的相关模型中使用静态属性,然后使用DropDownList for Html帮助器来构建它。我对数据的结构感到困惑。是否希望每个用户都能选择
AbsolutePress
的首选项和
FluidFlow
的首选项,并将这些值用于格式化应用程序中其他数据的显示?@barrik,UOMMaster表中包含了下拉列表的可能选项。每个用户都将其首选设置存储在
ICollection UOMDefaults
@Stephen Muecke,yes。我想你明白了。由于该应用程序被世界上许多不同国家的用户使用,他们可能更喜欢公制计量单位,而不是美国计量单位标准。应用程序根据用户指定的性能/容量显示可用产品。根据你的评论,我想你理解我的意图。在这种情况下,我认为你的数据库结构不正确,或者至少不理想。我将很快发布一个答案,并说明我的方法。我的方法是动态的方法。我知道你的设计会奏效,但每次添加新的首选项时,我都会编辑控制器动作、模型和视图。它还增加了最初的编码。我的方法允许我使用
foreach(user.UOMDefaults中的var preference)
遍历用户的首选项。这一点似乎很清楚,但我不明白的是如何将所有UOMMaster定义分离为一个单独的下拉列表。此外,我认真考虑过使用枚举。为了收支平衡,UOMMasters表实际上包含更多的数据列。所有的转换也包括在内-比例和移位因子,所需的显示精度,等等。我正在创建一个类来包装执行所有转换的UOMDefaults。您为我添加了一些不错的考虑因素,但我觉得我决定不象您在回答中那样单独定义这些偏好。毕竟,它们可能有几十个,而且它们的行(列)比我上面显示的更详细。好的,尽管我仍然会为每个选项类型创建表,例如,
AbsolutePressOptions:ID(PK)、Name、IsDefault(bit)、ScaleFactor、ShiftFactor、,etc
以便您可以检索所有的
绝对按Options
创建一个
选择列表
,以便在下拉列表中使用,然后将所选选项的ID值保存在
UserOptions
表的
AbsolutePressPreference
列中。我想我最大的障碍是找出如何检索UOMMasters首选项并将其分开,然后为每个首选项添加用户所选的首选项。我已经可以将整个UOMMasters检索到一个列表中,并且我可以很容易地为每个UOMMasters获取用户所需的首选项列表,但我只有两个列表。我只是不明白这是怎么回事
public class UserOptions
{
  public UserOptions()
  {
    // Set defaults
    AbsolutePressPreference = AbsolutePressOption.psi;
  }
  public AbsolutePressOption AbsolutePressPreference { get; set; }
  public FluidFlowOption FluidFlowPreference { get; set; }
}
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; }
}
[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);
}
@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" />
}
[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 })
}
@foreach (string preference in Model.UOMPreferences.OrderBy(p=>p.SortOrder)
                                                .Select(p=>p.MeasureId )
                                                .Distinct())
{
    var preferences = Model.UOMPreferences.Where(p=>p.MeasureId = preference);
....
     @Html.DropDown(preference, new SelectList(preferences, "Id", "UOMId"))
....
}