2

I'm trying to create controller with vies for entity framework. As model class I'm going to use Product class:

public class Product
{
    public int ProductId { get; set; }
    public int CategoryId { get; set; }
    public int ManufacturerId { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public decimal Price { get; set; }
    public string PhotoUrl { get; set; }
    public Category Category { get; set; }
    public Manufacturer Manufacturer { get; set; }
}

And like data context class this:

public class RetroGadgetEntities:DbContext
{
    public DbSet<Product> Products { get; set; }
    public DbSet<Category> Categories { get; set; }
}

The problem is that I get an error when trying to create controller "Unable to retrieve metadata for 'RetroGadget.Models.Product'". As I understand it is actualy thrown when code generator trying to create strongly typed view, but I can't figure out why.

UPD: Here is my Web.config.

  <connectionStrings>
   <add name="RetroGadgetCon" connectionString="Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=RetroGadget.Models.RetroGadgetEntities;Integrated Security=True;" providerName="System.Data.SqlClient"/>   
  </connectionStrings>
  <entityFramework>
    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
      <parameters>
        <parameter value="mssqllocaldb" />
      </parameters>
    </defaultConnectionFactory>
    <providers>
      <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
    </providers>
  </entityFramework>

UPD2

public class Product
{   
    [Key]
    public int ProductId { get; set; }
    public int CategoryId { get; set; }
    public int ManufacturerId { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public decimal Price { get; set; }
    public string PhotoUrl { get; set; }
    [ForeignKey("CategoryId")]
    public Category Category { get; set; }
    [ForeignKey("ManufacturerId")]
    public Manufacturer Manufacturer { get; set; }
}

Why this error thrown and what I can do with it?

Gleb
  • 1,412
  • 1
  • 23
  • 55

2 Answers2

1

Here are possible fixes you can do:

1) If you're using Code First & error message indicates Entity 'X' has no key defined or EntitySet 'X' is based on type 'Y' that has no keys defined, add primary key attribute (KeyAttribute) to model class property which serves as identity column:

using System.ComponentModel.DataAnnotations;

public class Product
{
    [Key] // add this attribute
    public int ProductId { get; set; }

    // other properties
}

Additionally, ensure that DbContext constructor contains reference to named connection string in web.config:

public class RetroGadgetEntities : DbContext
{
    public RetroGadgetEntities() : base("RetroGadgetCon")
    {
    }

    public DbSet<Product> Products { get; set; }
    public DbSet<Category> Categories { get; set; }
}

Afterwards, ensure all foreign keys & table relationships are arranged well (add ForeignKeyAttribute & ICollection if required).

2) If error message indicates Unrecognized element 'providers', this provider section in web.config possibly causing metadata problem on EF context when creating controller from a model (often occurs when you're downgrading default EF version used by template to previous one):

<providers>
    <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
</providers>

Try removing that provider part so that the entityFramework section becomes this:

<entityFramework>
    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
      <parameters>
        <parameter value="mssqllocaldb" />
      </parameters>
    </defaultConnectionFactory>
</entityFramework>

NB: The connection string section seems used invalid database location namespace as RetroGadget.Models.RetroGadgetEntities, try changing Initial Catalog to use a database name instead:

<add name="RetroGadgetCon" connectionString="Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=(database name);Integrated Security=True;" providerName="System.Data.SqlClient"/>

If the connection still not working with given LocalDB instance, add AttachDbFilename="(database path)\(database name).mdf" & use Data Source=(LocalDb)\v11.0 (depending on LocalDB version, see SQL Server connection string).

References:

Cannot create controller with Entity framework - Unable to retrieve metadata for ' '

Entity Framework: Unrecognized element 'providers' exception

Tetsuya Yamamoto
  • 24,297
  • 8
  • 39
  • 61
  • Thanks, but nothing works. 'RetroGadget.Models.RetroGadgetEntities' is actual db name(created by EF). And also I shuld mention that error message don't indicates anything, just 'Unable to retrieve metadata for 'RetroGadget.Models.Product' and nothing more. – Gleb Aug 03 '17 at 07:14
  • I'm not sure if the error doesn't contain anything after "Unable to provide metadata for X". Can you provide additional details and/or screenshot from the error? Also your `Product` class has no data annotations defined, possibly the error comes from it. – Tetsuya Yamamoto Aug 03 '17 at 08:07
  • What datails do you need? I can provide a screenshot but it is in russian. But there is nothing more on it, just error text I'v provided. – Gleb Aug 03 '17 at 09:28
  • @Gleb Usually any error message has exception details & stack trace related with it. Check system/application event log to see the detailed info for the error, I think just providing primary key attribute will fine in similar issues. – Tetsuya Yamamoto Aug 03 '17 at 10:02
  • I'v added attributes, you can see that in UPD2. But there is the same error. Also I haven't find visual studio(or its components) errors in application event log. – Gleb Aug 03 '17 at 10:52
1

Ok, I'v solved it. The actual problem was with linked classes.

public class Category
{
    [Key]
    public int CategoryId { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public List<Product> Products { get; set; }
}

public class Manufacturer
{
    [Key]
    public int ManufacturerId { get; set; }
    public string Name { get; set; }
}

Problem was that there was no field Products in Manufacturer class. So I'v changed this like this.

public class Manufacturer
{
    [Key]
    public int ManufacturerId { get; set; }
    public string Name { get; set; }
    public List<Product> Products { get; set; }
}
Gleb
  • 1,412
  • 1
  • 23
  • 55