我最近进入了Asp.Net MVC开发(使用MVC 6和Asp 5)。
我正在尝试在2个模型类之间创建关系。产品和类别。产品属于一个类别,因此一个类别可以包含许多产品。
这是我的型号代码:
public class Category
{
public int id { get; set; }
public string name { get; set; }
public virtual ICollection<Product> product { get; set; }
}
public class Product
{
public int id { get; set; }
public string name { get; set; }
public decimal price { get; set; }
public virtual Category category { get; set; }
}
然后我使用带有视图的实体框架从模型中创建了2个控制器,然后执行迁移。然后我对两者都进行了CRUD操作,但是问题是我无法将产品分配到类别。我只能使用生成的视图设置产品的名称和价格。
希望有人可以提供帮助。显然我期望某种下拉菜单在创建产品时显示所有类别,因此我可以将它们链接在一起。
感谢。
*编辑* ProductsController - 创建方法:
// POST: Products/Create
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Create(Product product)
{
if (ModelState.IsValid)
{
_context.Product.Add(product);
_context.SaveChanges();
return RedirectToAction("Index");
}
return View(product);
}
请再次注意,我并不是想手动添加功能。我试图让整个脚手架/迁移过程与对象关系一起工作,因此它可以自动为我生成它并加快我的开发过程。
*编辑2 * 产品型号更改为:
public class Product
{
public int ProductID { get; set; }
public string ProductName { get; set; }
public decimal ProductPrice { get; set; }
[ForeignKey("Category")]
public int CategoryID { get; set; }
public virtual Category category { get; set; }
}
现在,我将在创建产品时创建一个类别下拉列表。但是 - 即使我创建了一个类别,列表也是空的,所以仍然缺少某些东西?也许类别模型需要额外的信息?这是它在GET创建中显示列表的方式:
// GET: Products/Create
public IActionResult Create()
{
ViewData["CategoryID"] = new SelectList(_context.Category, "id", "category");
return View();
}
这只是一个空列表......几乎就在那里,但还没有。
答案 0 :(得分:1)
您的产品类应如下所示
public class Product
{
public int ProductID { get; set; }
public string ProductName { get; set; }
public decimal ProductPrice { get; set; }
[ForeignKey("Category")]
public int CategoryID {get;set;}
public virtual Category category { get; set; }
}
现在,您的Product表中将有一个列,用于存储它所属的类别。
要获得包含所有可用类别的下拉列表以启用选择,您可以尝试以下
ViewBag.CategoryID= new SelectList(db.Category, "CategoryID", "CategoryName");
在视图中,您可以按如下方式使用它
@Html.DropDownList("CategoryID", null, htmlAttributes: new { @class = "form-control" })
答案 1 :(得分:0)
产品需要包含CategoryId(外键)。那么你可以告诉EF关系的样子(尽管如果namings are done correct,EF可能会自己解决这个问题):
public class Category
{
public int CategoryId { get; set; }
public string Name { get; set; }
public virtual ICollection<Product> Products { get; set; }
}
public class Product
{
public int ProductId { get; set; }
public string Name { get; set; }
public int CategoryId { get; set; }
public virtual Category Category { get; set; }
}
public class StoreContext : DbContext
{
public DbSet<Category> Categories{ get; set; }
public DbSet<Product> Products { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// optionally, even EF can follow convention and detect 1-m relationship between product and category.
modelBuilder.Entity<Product>().HasRequired(p => p.Category)
.WithMany(c => c.Products)
.HasForeignKey(p => p.CategoryId);
}
}
创建新产品时,使用正确的值设置CategoryId属性,将其连接到类别。
您的ViewModel应该看起来像这样(可以包含您必须稍后映射的整个Product类或单个属性):
public class ProductViewModel
{
public ProductViewModel()
{
EditableProduct = new Product();
}
public List<SelectListItem> Categories { get; set; }
public Product EditableProduct { get; set; }
}
ProductController将填充所有类别并准备视图模型:
public ActionResult Edit(int? id)
{
var model = new ProductViewModel();
model.Categories = dbContext.Categories.Select(x => new SelectListItem() {Text = x.Name, Value = x.Id.ToString()}).ToList();
// check if product even exists
model.EditableProduct = id.HasValue ? dbContext.Products.Find(id.Value) : new Product();
return View(model);
}
[HttpPost, ValidateAntiForgeryToken]
public ActionResult Edit(ProductViewModel model)
{
// check validation
Product product;
if (model.EditableProduct.Id > 0)
product = dbContext.Products.Find(model.EditableProduct.Id);
else
{
product = new Product();
dbContext.Products.Add(product);
}
product.CategoryId = model.EditableProduct.CategoryId;
product.Name = model.EditableProduct.Name;
// add try/catch
dbContext.SaveChanges();
return RedirectToAction("Edit", new {id = product.Id});
}
Razor视图可以呈现类别:
@Html.DropDownListFor(x => x.EditableProduct.CategoryId, Model.Categories)
这是您可以遵循所有查找列表和一对多关系的一般模式。
建议:不要泄漏&#34;您的数据库/域模型进入视图。将name,id等属性放入View Model类,并在收到请求并对其进行验证时将它们映射到EF模型。尽量避免将Product对象放入视图模型中,就像我在本例中所做的那样!
答案 2 :(得分:0)
这似乎是MVC Scaffolding中的一个错误,您可以在此处找到更多详细信息: https://github.com/aspnet/Scaffolding/issues/149
在你看来尝试这样的事情:
@{ var categories = (IEnumerable<SelectListItem>)ViewData["CategoryID"]; }
<select asp-for="CategoryID" asp-items="categories" class="form-control"></select>
这为我解决了类似的问题。