[编辑] 此问题已解决!请参阅帖子末尾的说明。
[编辑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
结果是: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());
}
也许这个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();
}
}
}
您的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
}
}
然后Update-Database -Verbose
玩得开心!
答案 0 :(得分:34)
回答Adding custom MigrationHistory context ...
的解释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();
答案 1 :(得分:33)
使用MySQL Connector / Net 6.8和Entity Framework第6版,您可以使用MySQL内置的EF支持解决此问题。诀窍是告诉实体框架使用MySQL解析器。来自Connector/Net Developer Guide:
这可以通过三种方式完成:
在上下文类中添加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
答案 2 :(得分:9)
虽然ChAmp33n接受的答案已经解决了提问者提出的问题,但我认为在答案之后会有一些“突破”的变化。我已经应用了接受的答案,但例外仍然存在。
通过检查EF生成的SQL查询,我发现问题与表AspNetRoles中的表AspNetUsers和Name(varchar utf8 256)中的UserName(varchar utf8 256)有关,而HistoryRow的表很好。 / p>
所以以下代码解决了这个问题。
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();
}
}
为了澄清解决方案,这里是我正在使用的库:
此解决方案也适用于
答案 3 :(得分:2)
查看EF CodePlex网站上的this workitem。如果您使用的是EF6,则可以配置迁移历史记录表并缩短列数 - here是一篇展示如何执行此操作的文章。
答案 4 :(得分:2)
对于那些像我一样头疼的人,我自己找到了解决方案。 转到迁移文件(在我的例子中是201603160820243_Initial.cs),编辑所有maxLength:256到128.再次运行Update-database,它适用于我。
仍然不知道为什么nvarchar(256)(512字节)不满足767字节,并且更新不适用于键列。
答案 5 :(得分:0)
您指定的主键长度为450个unicode字符。在检查列大小限制时,MySQL假定字符大小最坏的情况 - 可能是2或4个字节,具体取决于您的字符集和排序规则 - 所以这些都是900或1800字节,都太长了。
主键实际上不应该是聚合键。主键控制表格在磁盘上的布局方式;这是表现自杀。使主键成为整数,并附加具有所需结构的辅助键。
答案 6 :(得分:0)
这是因为实体框架计算的外键名称可能太长。我们可以在migartion.cs文件中指定外键名。 ForeignKey()
方法的第四个参数是ForeignKeyName
。
默认情况下,它看起来像这样:
.ForeignKey("xxx", t => t.yyy) <br/>
Modify it as: <br/>
.ForeignKey("xxx", t => t.yyy,false, "YourForeignKeyName")