2016-02-15 6 views
1

Недавно я познакомился с разработкой Asp.Net MVC (с использованием MVC 6 и Asp 5).Asp.Net MVC 6 Entity Framework - отношения модели

Я пытаюсь создать связь между 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 для обоих, которые отлично работают, но проблема в том, что я не могу присвоить товар категории. Я могу установить только имя и цену продукта, используя сгенерированные представления.

Надеюсь, что кто-то может помочь. Очевидно, что я ожидаю какой-то раскрывающийся список, который показывает все категории при создании продукта, поэтому я могу связать их вместе.

Спасибо.

* EDIT * 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); 
    } 

Опять же, обратите внимание, что я не пытаюсь добавить функциональность вручную. Я пытаюсь заставить всю процедуру создания лесов/миграции работать с объектными отношениями, поэтому она может автоматически генерировать ее для меня и ускорять процесс разработки.

* EDIT 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: Products/Create 
    public IActionResult Create() 
    { 
     ViewData["CategoryID"] = new SelectList(_context.Category, "id", "category"); 
     return View(); 
    } 

который является только пустой список ... Почти, но не совсем еще.

+0

«Я не могу присвоить товар категории« Как вы попытались назначить его? Включите этот код, пожалуйста, –

+1

. У вашей таблицы продуктов есть столбец CategoryId? –

+2

Как сказал janina, использует CategoryId как внешний ключ. И, пожалуйста, поместите заглавные буквы в свои свойства, это методы, а не переменные. – OrcusZ

ответ

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

Теперь вы будете иметь столбец в вашей таблице продукта, который будет хранить, к какой категории он будет принадлежать.

Чтобы получить выпадающий список со всеми доступными Категории, чтобы разрешить выбор, вы можете попробовать следующее

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

А в представлении можно использовать следующим образом необходимо

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

Это приблизило меня! Теперь он действительно создает раскрывающийся список для категорий, когда я создаю новый продукт. ОДНАКО - выпадающий список пуст? См. Мое редактирование 2 сообщения для получения дополнительной информации. –

+0

'ViewData [" CategoryID "] = new SelectList (_context.Category," id "," name ");'. У вас нет ничего с категорией имен в классе категории mdoel. – Vini

+0

Я пробовал это, все еще не работая. Kinda чувствует себя странно, что строительные леса будут делать это следующим образом: ViewData ["CategoryId"] = новый SelectList (_context.Category, CategoryId "," Категория "); Заставляет меня чувствовать, что что-то по-прежнему не так с моими образцовыми отношениями .. просто не знаю, что. –

0

Продукт содержит CategoryId (внешний ключ).Тогда вы можете сказать EF, как отношения выглядит (хотя и EF, вероятно, понять, что само собой, если namings are done correct):

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 должен выглядеть следующим образом (может содержать целый класс товаров или отдельные свойства, которые вы должны карту позже):

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 в модель, как в этом примере!

+0

Не совсем то, что я ищу - как вы сами так говорите, EF должен делать это автоматически, и это то, что я хочу. Поэтому проблема должна быть в моих моделях и их отношениях, но не знаю, где. Прочитайте мое Редактирование, ответ ближе, но пока нет. –

+0

Теперь я привел полный пример. Что касается EF и картографии; EF будет знать, как правильно создавать отношения, только если вы соблюдаете соглашение об именах. В вашем вопросе вы не соблюдали соглашение, поэтому в этом случае вам необходимо помочь EF с дополнительной информацией о картографии. По моему опыту, вполне нормально полагаться на соглашение по умолчанию и автоматическое сопоставление только для простых моделей и схемы, но важно знать, как их настроить вручную! –

+0

Спасибо за ответ, но вы говорите, что EF будет делать это автоматически, если я буду следовать соглашениям об именах, которые, как вы говорите, я этого не сделаю, - тогда вы можете сказать мне, где я иду не так, чтобы я мог правильно принять конвенцию и он генерирует его автоматически? Честно говоря, я еще никогда не слышал об объекте «ViewModel», и я не верю, что что-то не так с передачей объекта модели в представление. –

0

Это кажется ошибка в 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> 

Это решается аналогичная проблема для меня.

Смежные вопросы