Asp.Net MVC 6实体框架 - 模型关系

时间:2016-02-15 09:50:40

标签: c# asp.net asp.net-mvc entity-framework

我最近进入了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();
    }

这只是一个空列表......几乎就在那里,但还没有。

3 个答案:

答案 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>

这为我解决了类似的问题。