繁体   English   中英

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

[英]Asp.Net MVC 6 Entity Framework - Model relationships

我最近开始研究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();
    }

这只是一个空列表...快到了,但还没有。

您的产品类别应如下所示

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; }
}

现在,您的“产品”表中将有一个列,该列将存储该列所属的类别。

要获得包含所有可用类别的下拉列表以启用选择,您可以尝试以下操作

 ViewBag.CategoryID= new SelectList(db.Category, "CategoryID", "CategoryName");

在视图中,您可以按以下方式使用它

@Html.DropDownList("CategoryID", null, htmlAttributes: new { @class = "form-control" })

产品需要包含CategoryId(外键)。 然后,您可以告诉EF关系的外观(即使EF 正确地命名也可能会自己弄清楚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});
}

然后,剃刀视图可以呈现类别:

@Html.DropDownListFor(x => x.EditableProduct.CategoryId, Model.Categories)

这是您可以对所有查找列表和一对多关系遵循的常规模式。

忠告:不要将数据库/域模型“泄漏”到视图中。 将名称,id等属性放入View Model类,并在收到请求并对其进行验证后将它们映射到EF模型。 尽量避免像本例中那样将Product对象放入视图模型中!

这似乎是MVC脚手架中的错误,您可以在此处找到更多详细信息: https : //github.com/aspnet/Scaffolding/issues/149

在您看来,尝试以下操作:

@{ var categories = (IEnumerable<SelectListItem>)ViewData["CategoryID"]; }
<select asp-for="CategoryID" asp-items="categories" class="form-control"></select>

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM