user2117713
user2117713

Reputation: 97

A specified Include path is not valid. The EntityType 'SpiceShop.Models.Product' does not declare a navigation property with the name 'Products'

I Have Database that contains 2 tables

TABLE Categories (CategoriesId, Name, Description)
TABLE Products (ProductId, CategoriesId, Title, ProductImageUrl)

Categories is linked to Products by CategoriesId.

I am trying to use LINQ to get all of a particular Title.

 public ActionResult Browse(string categories)
 {
     var spices = spiceDB.Products.Include("Products").Single(p => p.Title == categories);                 
     return View(spices);
 }

Product Model

namespace SpiceShop.Models
{
    public class Product
    {
        [Key]
        public int ProductId { get; set; }

        public int CategoriesId { get; set; }
        public string Title { get; set; }

        public string ProductImageUrl { get; set; }
        public List <Categorie> Name { get; set; }
    }
}

Categorie Model

namespace SpiceShop.Models
{
    public class Categorie
    {
        [Key]
        public int CategoriesId { get; set; }
        public string Name  { get; set; }

        public string Description { get; set; }
        //public List<Product> ProductId { get; set; }
        public List<Product> Products { get; set; }
    }
}

Upvotes: 3

Views: 17363

Answers (2)

Merenzo
Merenzo

Reputation: 5156

Edit:

It looks like your View requires a Model that is a single object of type "Product".

Also, I have tried to give each of my identifiers/variables a name that best conveys their meaning and intent.


Edit 2:

Please note that changing any input parameter names on a method will require a corresponding change in your View code that calls the method.
In MVC, Action-Method parameters are automatically mapped.
Your debug shows a URL of Browse?categories=Sauces, which is automatically mapped to the method "Browse" with input parameter categories set to "Sauces". But (my version of) the Browse method is expecting a categoryName parameter, not categories. So you will need to make sure that URL Attribute and the Method Parameter have exactly the same name.


So if you really need to pass the selected Category's Name as the input parameter:

public ActionResult Browse(string categoryName)
{
    // Gets the CategoryId for the given categoryName, or zero if not found.
    var categoryId = spiceDB.Categories
        .Where(c => c.Name == categoryName)
        .Select(c => c.CategoriesId)
        .FirstOrDefault();

    // Gets the first Product (only) for the specified categoryId.
    var firstProduct = category.Products
        .FirstOrDefault(p => p.CategoriesId == categoryId);

    return View(firstProduct);
}

However, a much more common usage scenario for supporting this type of "parent-child" relationship would be:

  • Your Category List invokes a query by ID when clicked, not a query by Name (i.e. 3, not "Pickles")
  • Your View supports all the related Products, not just the first one (i.e. a model of type List<Product>, not just Product)

e.g.

public ActionResult Browse(int categoryId)
{
    var products = spiceDB.Products
        .Where(p => p.CategoriesId == categoryId) 
        .ToList();

    return View(products);
}

i.e. making your Product List more comprehensive, and your data access code simpler and more efficient.

Upvotes: 4

Felipe Castro
Felipe Castro

Reputation: 1613

Just remove the .Include("Products"), that's not how it's used.

The error is clear, there is no "Products" property at your "Product" model.

Upvotes: 6

Related Questions