这可能很简单,但我似乎无法自己解决这个问题。 我创建了一个简单的数据库和实体模式,看起来像这样
我正在尝试创建一个允许我添加新订单的创建表单。我总共有3个表,所以我想要的是允许此人输入订单日期的表单,还有一个下拉列表,允许我从产品表中选择产品
我希望能够创建一个Add或Edit视图,允许我将OrderDate插入OrderTable,并将OrderID和选定的ProductID插入OrderProduct。
我需要在这做什么步骤。
我创建了一个OrderController并勾选了“添加操作”,然后添加了一个看起来像这样的创建视图
@model Test.OrderProduct
@{
ViewBag.Title = "Create2";
}
<h2>Create2</h2>
<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
@using (Html.BeginForm()) {
@Html.ValidationSummary(true)
<fieldset>
<legend>OrderProduct</legend>
<div class="editor-label">
@Html.LabelFor(model => model.OrderID)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.OrderID)
@Html.ValidationMessageFor(model => model.OrderID)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.ProductID)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.ProductID)
@Html.ValidationMessageFor(model => model.ProductID)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
这将创建包含OrderID和ProductID文本框的视图,但不包含日期。
我的控制器CreatePost尚未更改
[HttpPost]
public ActionResult Create(FormCollection collection)
{
try
{
var data = collection;
// TODO: Add insert logic here
// db.Orders.AddObject(collection);
return RedirectToAction("Index");
}
catch
{
return View();
}
}
我的问题是,
1.如何将ProductID文本框换成从Product填充的下拉列表 2.如何从FormCollection集合中获取数据?我只想到了一个foreach,但我不知道如何获得强类型名称
对新手的任何帮助都会非常有帮助。
谢谢!
答案 0 :(得分:25)
首先,不要绑定到订单实体。永远不要绑定到EF对象,总是尝试使用 ViewModel 。使View的生活更简单,这就是目标。
所以,有一个像这样的ViewModel:
public class CreateOrderViewModel
{
public int OrderId { get; set; }
public DateTime OrderDate { get; set; }
public int SelectedProductId { get; set; }
public IEnumerable<SelectListItem> Products { get; set; }
}
现在就是这样。
在[HttpGet]
控制器操作中将其返回到您的视图:
[HttpGet]
public ActionResult Create()
{
var model = new CreateOrderViewModel
{
Products = db.Products
.ToList() // this will fire a query, basically SELECT * FROM Products
.Select(x => new SelectListItem
{
Text = x.ProductName,
Value = x.ProductId
});
};
return View(model);
}
然后渲染出产品列表:(不包括基本HTML)
@model WebApplication.Models.CreateOrderViewModel
@Html.DropDownListFor(model => model.SelectedProductId, Model.Products)
我唯一不知道该怎么做的是绑定到DateTime字段。我猜你需要一个扩展方法(HTML Helper),它会渲染一个日期选择器或其他东西。对于此视图(创建新订单),只需默认为DateTime.Now
。
现在,进入[HttpPost]
控制器操作:
[HttpPost]
public ActionResult Create(CreateOrderViewModel model)
{
try
{
// TODO: this manual stitching should be replaced with AutoMapper
var newOrder = new Order
{
OrderDate = DateTime.Now,
OrderProduct = new OrderProduct
{
ProductId = SelectedProductId
}
};
db.Orders.AddObject(newOrder);
return RedirectToAction("Index");
}
catch
{
return View();
}
}
现在,我也认为您的EF模型需要工作。
对我来说(以英语说),产品可以有很多订单,而订单可以有很多产品。
所以,它应该是多对多的。目前,这是一个带有冗余连接表的1-1。你是从DB生成的吗?如果是这样,您的DB可能需要工作。
您应该在订单实体上拥有一个名为产品的导航属性,该属性引用产品的集合,通过静默连接实现到多对多的连接表。
这也意味着你不再拥有DropDownList,而是MultiSelectDropDownList。
答案 1 :(得分:2)
谢谢克雷格。你在MVC的几天(截至发布时)已经解决了我几天试图从DropDownListFor获取所选值的问题。
我在创建视图中获取DDLF的选定值没有问题,但编辑视图是完全不同的事情 - 我尝试的任何内容都不会在Post中获得所选值。我注意到所选的值潜伏在ModelState的AttemptedValue中,所以Dr.Google在这里引用了我。
我认为这是
@Html.DropDownList(model => model.ContentKeyID, Model.ContentKeys, Model.ContentKeyName)
其中ContentKeys是通过ViewModel从DB填充的SelectList,而ContentKeyName是选择的名称。
奇怪的是,我在视图中以相同的方式填充了另一个DDL。这个工作。为什么,我不知道。它是表格上的第二个DDL,但我看不出它有所作为。
我在其他地方读到可能是因为我使用Guids作为Id,但这似乎没有什么区别 - 我改为Int32,但不认为我必须 - 我认为这是枚举不同意DDLF。 Nullables似乎没有任何区别。
现在我已将表单集合添加到Post ActionResult,并使用
获取所选值-view
@Html.DropDownList("ContentKey", Model.ContentKeys)
-in controller(Post)
contentKeyId = int.Parse(form.GetValue("ContentKey").AttemptedValue);
一切都很好,我可以继续做更多令人兴奋的事情。为什么最简单的事情会让你忍受这么久?
答案 2 :(得分:1)
在过去的一天左右,我一直在努力解决这个问题。我将分享我有限的知识,希望它能帮助别人。
请注意,我使用带有预填充列表的单例来保持我的示例应用程序较小(即没有EF或DB交互)。
要显示ProductList,您需要具有包含ProductList的ViewBag或ViewData项。 您可以使用类似
的内容在Controller中进行设置 ViewData["ProductList"] = new SelectList(Models.MVCProduct.Instance.ProductList, "Id", "Name", 1);
然后将您的视图更新为:
<div class="editor-field">@Html.DropDownList("ProductList")</div>
对于发布/创建/更新步骤,您需要查看FormCollection以获取结果。阅读其他帖子听起来像曾经是这里的一个错误,但现在已经修复,所以确保你有最新的。对于我的示例,我有一个DropDownList for Product,所以我只获得所选的Id,然后在我的列表中搜索该产品。
[HttpPost]
public ActionResult Create(FormCollection form )//Models.MVCOrder newOrder)
{
MVC.Models.MVCOrder ord = Models.MVCOrder.Instance.CreateBlankOrder();
//Update order with simple types (e.g. Quantity)
if (TryUpdateModel<MVC.Models.MVCOrder>(ord, form.ToValueProvider()))
{
ord.Product = Models.MVCProduct.Instance.ProductList.Find(p => p.Id == int.Parse(form.GetValue("ProductList").AttemptedValue));
ord.Attribute = Models.MVCAttribute.Instance.AttributeList.Find(a => a.Id == int.Parse(form.GetValue("attributeId").AttemptedValue));
UpdateModel(ord);
return RedirectToAction("Index");
}
else
{
return View(ord);
}
}
我过去几天才开始研究MVC3,所以对任何有关改进上述内容的建议都表示赞赏。