具有MySql和迁移的实体框架失败,因为"最大密钥长度为767字节"

Ric*_*per 33 c# mysql entity-framework

[编辑]这个问题解决了!请参阅帖子末尾的说明.

[编辑2]好的,这个线程已经过时了,MySQL Connector的新版本已经使用MySQL EF解析器处理了这个问题.在这个帖子上寻找@KingPong的答案.不过,我还没有测试过.

我正在尝试使用MySql和EntityFramework进行迁移,但似乎有些错误.

当我进入Update-Database -Verbose包管理器控制台时,EF执行一些将"镜像"我的模型类的查询,一切都很完美,但是EF尝试执行此查询:

create table `__MigrationHistory` 
(
  `MigrationId` varchar(150)  not null 
  ,`ContextKey` varchar(300)  not null 
  ,`Model` longblob not null 
  ,`ProductVersion` varchar(32)  not null
  ,primary key ( `MigrationId`,`ContextKey`) 
 ) engine=InnoDb auto_increment=0
Run Code Online (Sandbox Code Playgroud)

结果是: Specified key was too long; max key length is 767 bytes

我试图将我的数据库排序规则更改为utf-8,但仍然相同.也许关键长度是450个字符,做UTF-8数学(​​我可能错了),我认为它试图创建一个大约1800字节长度的密钥.

由于我是EF的新手,我遵循了一些教程,他们告诉我这样做:

    public Configuration()
    {
        AutomaticMigrationsEnabled = false;

        SetSqlGenerator("MySql.Data.MySqlClient", new MySql.Data.Entity.MySqlMigrationSqlGenerator());
    }
Run Code Online (Sandbox Code Playgroud)

也许这个SQL生成器做错了,或者EF本身要求生成器生成一个高达767字节的密钥.

我该如何解决这个问题,避免这个问题并让它与MySql一起使用?

[编辑] 好的,这个问题解决了.你必须告诉EF它必须改变它生成__MigrationHistory表的方式.

我做了什么:首先,MySqlHistoryContext.cs用这个内容创建一个名为(或任何你想要的)文件:

...
using System.Data.Common;
using System.Data.Entity;
using System.Data.Entity.Migrations.History;


namespace [YOUR NAMESPACE].Migrations //you can put any namespace here, but be sure you will put the corret using statement in the next file. Just create a new class :D
{
    public class MySqlHistoryContext : HistoryContext
    {

        public MySqlHistoryContext(DbConnection connection, string defaultSchema):base(connection,defaultSchema)
        {

        }

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

            modelBuilder.Entity<HistoryRow>().Property(h => h.MigrationId).HasMaxLength(100).IsRequired();
            modelBuilder.Entity<HistoryRow>().Property(h => h.ContextKey).HasMaxLength(200).IsRequired(); 
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

你可能有一个名为Configuration.cs您的内部Migrations文件夹.如果是,请进行必要的调整,否则创建新文件.实际上,如果您没有此文件,您将无法获得此错误,因为EF会在您创建时自动创建它Add-Migration [name].

namespace [YOUR NAMESPACE].Migrations
{
    using System;
    using System.Data.Entity;
    using System.Data.Entity.Migrations;
    using System.Linq;

    internal sealed class Configuration : DbMigrationsConfiguration<CodeFirstMySql.Models.Context>
    {
        public Configuration()
        {
            AutomaticMigrationsEnabled = false;

            SetSqlGenerator("MySql.Data.MySqlClient", new MySql.Data.Entity.MySqlMigrationSqlGenerator()); //it will generate MySql commands instead of SqlServer commands.

            SetHistoryContextFactory("MySql.Data.MySqlClient", (conn, schema) => new MySqlHistoryContext(conn, schema)); //here s the thing.



        }

        protected override void Seed(CodeFirstMySql.Models.Context context){}//ommited
    }
}
Run Code Online (Sandbox Code Playgroud)

然后Update-Database -Verbose玩得开心!

ChA*_*33n 35

回答从添加自定义MigrationHistory上下文释义...

EF6使用MigrationHistory表来跟踪模型更改并确保数据库架构和概念架构之间的一致性.默认情况下,此表不适用于MySQL,因为主键太大.要解决此问题,您需要缩小该表的密钥大小.

从本质上讲,EF6允许您使用Fluent API修改MigrationId/ContextKey索引列的密钥大小,如下所示:

modelBuilder.Entity<HistoryRow>().Property(h => h.MigrationId).HasMaxLength(100).IsRequired();
modelBuilder.Entity<HistoryRow>().Property(h => h.ContextKey).HasMaxLength(200).IsRequired();
Run Code Online (Sandbox Code Playgroud)

完整说明在这里......


Kin*_*ong 33

使用MySQL Connector/Net 6.8和Entity Framework版本6,您可以使用MySQL对EF的内置支持来解决此问题.诀窍是告诉实体框架使用MySQL解析器.来自Connector/Net开发人员指南:

这可以通过三种方式完成:

  • 在上下文类中添加DbConfigurationTypeAttribute:

    [DbConfigurationType(typeof(MySqlEFConfiguration))]
  • 在应用程序启动时调用DbConfiguration.SetConfiguration(new MySqlEFConfiguration())

  • 在配置文件中设置DbConfiguration类型:

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

也可以创建自定义DbConfiguration类并添加所需的依赖项解析器.

当我按照这些说明(我使用配置文件方法)时,表已成功创建.它使用以下DDL:

create table `__MigrationHistory` (
  `MigrationId` nvarchar(150) not null,
  `ContextKey` nvarchar(300)  not null,
  `Model` longblob not null,
  `ProductVersion` nvarchar(32) not null,
  primary key ( `MigrationId`)
) engine=InnoDb auto_increment=0
Run Code Online (Sandbox Code Playgroud)


ZZZ*_*ZZZ 9

虽然ChAmp33n接受的答案解决了提问者提出的问题,但我认为在答案之后会有一些"破坏性"的变化.我已经应用了接受的答案,但例外仍然存在.

通过检查EF生成的SQL查询,我发现该问题与表AspNetRoles中的表AspNetUsers和Name(varchar utf8 256)中的UserName(varchar utf8 256)有关,而HistoryRow的表很好.

所以以下代码解决了这个问题.

    public class WebPortalDbContext : IdentityDbContext<ApplicationUser>
{
    public WebPortalDbContext()
        : base("IdentityConnection")
    {

    }

    public static WebPortalDbContext Create()
    {
        return new WebPortalDbContext();
    }

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

        modelBuilder.Entity<Microsoft.AspNet.Identity.EntityFramework.IdentityRole>()
            .Property(c => c.Name).HasMaxLength(128).IsRequired();

        modelBuilder.Entity<Microsoft.AspNet.Identity.EntityFramework.IdentityUser>().ToTable("AspNetUsers")//I have to declare the table name, otherwise IdentityUser will be created
            .Property(c => c.UserName).HasMaxLength(128).IsRequired();
    }


}
Run Code Online (Sandbox Code Playgroud)

为了澄清解决方案,这里是我使用的库:

  1. EF 6.1.0
  2. Microsoft ASP.NET Identity EntityFramework 2.0.0
  3. ASP.NET Identity Owin 2.0.0
  4. MySql .NET库6.8.3

而这个解决方案也适用于

  1. EF 6.1.1
  2. Microsoft ASP.NET Identity EntityFramework 2.0.1
  3. ASP.NET Identity Owin 2.0.1