19

MVC4 + Entity Framework 4.4 + MySql + POCO/Code First

I'm setting up the above configuration .. here are my classes:

namespace BTD.DataContext
{
public class BTDContext : DbContext
{

    public BTDContext()
        : base("name=BTDContext")
    {

    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        //modelBuilder.Conventions.Remove<System.Data.Entity.Infrastructure.IncludeMetadataConvention>();
    }

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

    public DbSet<ProductImage> ProductImages { get; set; }        


}
}

namespace BTD.Data
{
[Table("Product")]
public class Product
{
    [Key]
    public long ProductId { get; set; }

    [DisplayName("Manufacturer")]
    public int? ManufacturerId { get; set; }

    [Required]
    [StringLength(150)]
    public string Name { get; set; }

    [Required]
    [DataType(DataType.MultilineText)]
    public string Description { get; set; }

    [Required]
    [StringLength(120)]
    public string URL { get; set; }

    [Required]
    [StringLength(75)]
    [DisplayName("Meta Title")]
    public string MetaTitle { get; set; }

    [DataType(DataType.MultilineText)]
    [DisplayName("Meta Description")]
    public string MetaDescription { get; set; }

    [Required]
    [StringLength(25)]
    public string Status { get; set; }

    [DisplayName("Create Date/Time")]
    public DateTime CreateDateTime { get; set; }

    [DisplayName("Edit Date/Time")]
    public DateTime EditDateTime { get; set; }
}

[Table("ProductImage")]
public class ProductImage
{
    [Key]
    public long ProductImageId { get; set; }

    public long ProductId { get; set; }

    public long? ProductVariantId { get; set; }

    [Required]
    public byte[] Image { get; set; }

    public bool PrimaryImage { get; set; }

    public DateTime CreateDateTime { get; set; }

    public DateTime EditDateTime { get; set; }

}
}

Here is my web.config setup...

<connectionStrings>
<add name="BTDContext" connectionString="Server=localhost;Port=3306;Database=btd;User Id=root;Password=mypassword;" providerName="MySql.Data.MySqlClient" />
</connectionStrings>
  1. The database AND tables already exist...
  2. I'm still pretty new with mvc but was using this tutorial

The application builds fine... however when I try to add a controller using Product (BTD.Data) as my model class and BTDContext (BTD.DataContext) as my data context class I receive the following error:

Unable to retrieve metadata for BTD.Data.Product using the same DbCompiledModel to create context against different types of database servers is not supported. Instead, create a separate DbCompiledModel for each type of server being used.

I am at a complete loss - I've scoured google with almost every different variation of that error message above I can think of but to no avail.

Here are the things i can verify...

  1. MySql is working properly
  2. I'm using MySql Connector version 6.5.4 and have created other ASP.net web forms + entity framework applications with ZERO problems

I have also tried including/removing this in my web.config:

<system.data>
<DbProviderFactories>
  <remove invariant="MySql.Data.MySqlClient"/>
  <add name="MySQL Data Provider" invariant="MySql.Data.MySqlClient" description=".Net Framework Data Provider for MySQL" type="MySql.Data.MySqlClient.MySqlClientFactory, MySql.Data, Version=6.5.4.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d" />
</DbProviderFactories>

I've literally been working on this bug for days - I'm to the point now that I would be willing to pay someone to solve it.. no joke... I'd really love to use MVC 4 and Razor - I was so excited to get started on this, but now i'm pretty discouraged - I truly appreciate any help/guidance on this!

Also note - i'm using Entityframework from Nuget...

Another Note

I was using the default visual studio template that creates your MVC project with the account pages and other stuff. I JUST removed all references to the added files because they were trying to use the "DefaultConnection" which didn't exist - so i thought those files may be what was causing the error - however still no luck after removing them -

I just wanted to let everyone know i'm using the visual studio MVC project template which pre-creates a bunch of files. I will be trying to recreate this all from a blank MVC project which doesn't have those files - i will update this once i test that

UPDATE TO USING VS MVC Basic Template: Same error resulted - still no solution

ANOTHER PERSON EXPERIENCING THE SAME PROBLEM

Right here is another stackoverflow question that mimics mine - however I tried his solution to no avail - maybe someone else who is having this same problem can benefit from the link

UPDATE

I recently just tried putting this into MS Sql Server and the view scaffolding adds fine with no error - so I'm not sure if its my MySql database or connection string or what... driving me nuts..

Other References

It appears someone else is having the same issues I am - the only difference is they are using sql server - I tried tweaking all my code to follow the suggestions on this stackoverflow question/answer here but still to no avail

POSSIBLE FIX???

So this is weird... after hooking it up to MS Sql Server and adding the controller, then reverting the connection string to MySql it is actually WORKING with MySql... what the heck!??

So it seems that when you try to add your controller and the view scaffolding (is that the right phrase?) is added WITH the mysql connection string it fails...however if you hook it up to a sql server db, generate the scaffolding/controller, then revert to mysql connection string it works.... ?!?!

Community
  • 1
  • 1
99823
  • 2,407
  • 7
  • 38
  • 60
  • What are you using for a `DatabaseInitializer`? I bet you `CreateDatabaseIfNotExists`, `DropCreateDatabaseWhenModelChanges` or `DropCreateDatabaseAlways` runs in to trouble when ported over to MySQL (suppose a schema change or model difference). May have to make your own if you're not using SQL-Server – Brad Christie Sep 23 '12 at 18:14
  • I'm not using a DatabaseInitializer - everything you see in the BTDContext class is it - the database already exists in MySql - i was under the impression that in Code First if the database was found and tables were found it would automatically not try to create the DB/tables – 99823 Sep 23 '12 at 18:22
  • Another thing to note is that i had this working at one point, then it suddenly stopped working - i'm not sure what was changed but I know it CAN work... as it did previously – 99823 Sep 23 '12 at 18:34
  • 1
    My educated guess is that there is a difference that EF caught between the model(s) and the database; Something that EF wants to take care of (resurrect and update) but is unable to because it doesn't know how to proceed in MySQL. Try creating (and specifying) a customer `IDatabaseInitializer` and step through to see if/when `InitializeDatabase` is called. Within this method you can then check If `Database`.[`CompatibleWithModel`](http://msdn.microsoft.com/en-us/library/system.data.entity.database.compatiblewithmodel(v=vs.103).aspx) – Brad Christie Sep 23 '12 at 19:15
  • Hi Brad - I appreciate your idea - i'm going to try that now - do you happen to have any sources for sample code on that by chance? thanks again – 99823 Sep 23 '12 at 21:14
  • 1
    The only way I could workaround this was commenting out the DbContext class constructor and commenting out the connection string in the web.config file. After generating the Controller, I removed undid the comments and carried on. I think there are issues with the MySql connector and EF. – Justin Skiles Dec 20 '12 at 17:54

6 Answers6

25

It seems that MVC4 Controller scaffolding is not properly recognizing MySql Connection String. Change the connection string as shown below when generating EF CRUD code for Controllers:

<connectionStrings>
    <add name="BTDContext" connectionString="Data Source=host_name;Database=database_name;uid=user_id;pwd=password;" providerName="System.Data.SqlClient" /> 
</connectionStrings>

Change it back to standard when running the application:

<connectionStrings>
    <add name="BTDContext" connectionString="Data Source=host_name;Database=database_name;uid=user_id;pwd=password;" providerName="MySql.Data.MySqlClient" /> 
</connectionStrings>

Note the change, provider name.

imesh
  • 1,374
  • 1
  • 15
  • 18
  • This fixed my problem where it was refusing to build a controller unless I switched from the MySQL connector string to a (fake) SqlClient one. Switched it back after adding the controller and now everything works. Thanks. – Matt Burland Mar 01 '13 at 15:19
  • For me it was not enough to just switch to a fake SqlClient connection. I had to actually create the MSSQL database to get it to create the controller scaffolding. – ManicBlowfish Sep 19 '13 at 21:31
  • 1
    This worked for me too when using SQLite data provider. I just switched the provider to SqlClient generated my controller and switched back to SQLite. – maulik13 Jan 06 '14 at 14:59
10

The imesh suggesting almost solve my problem, but additionally I temporary commented line

[DbConfigurationType(typeof(MySqlEFConfiguration))]

which was in DBContext class. And of course after creation controller this line should be uncommented and change back System.Data.SqlClient to MySql.Data.MySqlClient in config file.

Yurko
  • 101
  • 1
  • 3
  • After this I had to rebuild as in @AronVanAmmers answer – OneHoopyFrood Apr 29 '15 at 20:48
  • Thank you. Only commenting out the line in the context file saved me after 2 hours oftrying to figure out what I was doing wrong – Shreyas Jul 13 '15 at 20:20
  • This solved my problem too. I am using MySQL. I just created the SQLServer connection string and commented out the DbConfigurationType attribute and the scaffolding wizard worked. Thanks for saving me endless aggravation. – Krafty Nov 28 '16 at 01:55
10

Using VS 2013, MySQL Connector/NET 6.9.6, Entity Framework 6, Web API 2.2 and MySQL server 5.7 I had to combine the answers to prevent the error about "Unable to retrieve metadata".

To successfully add a controller to a .NET project that uses a MySQL connection, do the following:

  1. Temporarily add a connection string with System.Data.SqlClient as the providerName, and comment the one for MySQL. It doesn't matter whether the connection string is valid.
  2. Ensure that MySqlEFConfiguration isn't enabled in any way.
  3. Rebuild.

About the second point, the MySQL documentation on using Connector/NET with EF6 states three possible ways to enable the MySqlEFConfiguration. Ensure that none of these are enabled while adding controllers using the VS template.

  1. Adding the DbConfigurationTypeAttribute on the context class:

[DbConfigurationType(typeof(MySqlEFConfiguration))]

  1. Calling DbConfiguration.SetConfiguration(new MySqlEFConfiguration()) at the application startup

  2. Set the DbConfiguration type in the configuration file:

<entityFramework codeConfigurationType="MySql.Data.Entity.MySqlEFConfiguration, MySql.Data.Entity.EF6">

AronVanAmmers
  • 1,668
  • 20
  • 24
1

I tested also around this bug and saw an other problem.

Following code is in my Web.config (without, it don't work):

<entityFramework codeConfigurationType="MySql.Data.Entity.MySqlEFConfiguration, MySql.Data.Entity.EF6">

Changed it to:

<entityFramework>

Works for me... add the scaffolding and then change it back

Suplanus
  • 1,523
  • 16
  • 30
0

I've been having the same problem using EF 4.3.1 and MySql Connecter/Net 6.6.4.0

This worked for me, no need to connect to a different db or extra code in the Context class.

Add this between the entityFramework tags in your web.config file when you want to build a scaffold:

<defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework">
  <parameters>
    <parameter value="Data Source=.\SQLEXPRESS; Integrated Security=True; MultipleActiveResultSets=True" />
  </parameters>
</defaultConnectionFactory>

Then comment the above code out when you want to run migrations and vice versa.

So you web.config will look like so:

<entityFramework>
  <contexts>
    <context type="ApptManager.Models.AppointmentsManagerContext, ApptManager">
      <databaseInitializer type="System.Data.Entity.MigrateDatabaseToLatestVersion`2[[ApptManager.Models.AppointmentsManagerContext, ApptManager], [ApptManager.Migrations.Configuration, ApptManager]], EntityFramework" />
    </context>
  </contexts>
  <!--<defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework">
    <parameters>
      <parameter value="Data Source=.\SQLEXPRESS; Integrated Security=True; MultipleActiveResultSets=True" />
    </parameters>
  </defaultConnectionFactory>-->
</entityFramework>

This is quite ridiculous how .NET developers have to jump through some arduous hoops in order to get their code working.

Working example

https://github.com/dublinan/mvc-mysql-ef-example

Links to my github project

Andre Dublin
  • 1,148
  • 1
  • 16
  • 34
0

Please try using the

System.ComponentModel.DataAnnotations

namespace along with the [Key] attribute on the EDM class members.

It worked for me.

Soul
  • 67
  • 6
Abhinaw
  • 35
  • 5