Já havia me deparado com esse erro anteriormente em um projeto Laravel. Nesse cenário a solução foi bem simples bastando editar o AppServiceProvider e definir o tamanho máximo para strings no método boot:
use Illuminate\Support\Facades\Schema;
public function boot()
{
Schema::defaultStringLength(191);
}
Hoje tive o mesmo problema em um projeto .Net Core, o que me fez procurar por uma solução direta no MySQL sem precisar alterar o tamanho da string pelo código.
Descobri que não existe uma solução definitiva no banco de dados já que o MySQL tem um limite de 767 bytes usando a engine InnoDB e 1000 bytes para a engine MYISAM, nesse caso o jeito é resolver o problema no código.
No projeto estou usando o Identity para autenticação dos usuários e ao gerar as tabelas o limite de bytes é estourado:
fail: Microsoft.EntityFrameworkCore.Database.Command\[20102\]
Failed executing DbCommand (1ms) \[Parameters=\[\], CommandType='Text', Comma
ndTimeout='30'\]
CREATE TABLE \`AspNetUserLogins\` (
\`LoginProvider\` varchar(767) NOT NULL,
\`ProviderKey\` varchar(767) NOT NULL,
\`ProviderDisplayName\` text NULL,
\`UserId\` varchar(767) NOT NULL,
PRIMARY KEY (\`LoginProvider\`, \`ProviderKey\`),
CONSTRAINT \`FK\_AspNetUserLogins\_AspNetUsers\_UserId\` FOREIGN KEY (\`User
Id\`) REFERENCES \`AspNetUsers\` (\`Id\`) ON DELETE CASCADE
);
MySql.Data.MySqlClient.MySqlException (0x80004005): Specified key was too long;
max key length is 1000 bytes
Podemos ver que ao criar a tabela AspNetUserLogins o Identity define um tamanho que ultrapassa o máximo permitido pela engine do MySQL.
Para resolver o problema vamos alterar a forma que o Identity define o tamanho dos campos para criação das tabelas. Para isso iremos sobrescrever o método OnModelCreating no DbContext da aplicação:
public class ApplicationDbContext: IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<ApplicationUser>(entity => {
entity.Property(m => m.Id).HasMaxLength(110);
entity.Property(m => m.Email).HasMaxLength(127);
entity.Property(m => m.NormalizedEmail).HasMaxLength(127);
entity.Property(m => m.NormalizedUserName).HasMaxLength(127);
entity.Property(m => m.UserName).HasMaxLength(127);
});
modelBuilder.Entity<IdentityRole>(entity => {
entity.Property(m => m.Id).HasMaxLength(200);
entity.Property(m => m.Name).HasMaxLength(127);
entity.Property(m => m.NormalizedName).HasMaxLength(127);
});
modelBuilder.Entity<IdentityUserLogin<string>>(entity =>
{
entity.Property(m => m.LoginProvider).HasMaxLength(127);
entity.Property(m => m.ProviderKey).HasMaxLength(127);
});
modelBuilder.Entity<IdentityUserRole<string>>(entity =>
{
entity.Property(m => m.UserId).HasMaxLength(127);
entity.Property(m => m.RoleId).HasMaxLength(127);
});
modelBuilder.Entity<IdentityUserToken<string>>(entity =>
{
entity.Property(m => m.UserId).HasMaxLength(110);
entity.Property(m => m.LoginProvider).HasMaxLength(110);
entity.Property(m => m.Name).HasMaxLength(110);
});
}
}
Com isso reduzimos o tamanho dos campos criados possibilitando a criação das tabelas no MySQL.