I'm trying to deploy my ASP.NET Core website on a production server, hosted with Plesk. I have 2 projects in my solution: 1 containing my DbContext, 1 containing my web project.
I generated migrations for my DbContext:
dotnet ef migrations add AddIdentity --project ..\MyProject.Data
Then I generated a production migration script as mentioned in the docs (https://learn.microsoft.com/en-us/ef/core/miscellaneous/cli/dotnet#dotnet-ef-migrations-script)
dotnet ef migrations script --idempotent --output "MigrationScripts\AddIdentity.sql" --context MyDbContext --project ..\MyProject.Data
Then I navigated to the SQL utility on my production server (MyLittleAdmin) and pasted the generated SQL script in it. This succeeds but I get the following error:
Warning! The maximum key length for a clustered index is 900 bytes. The index 'PK_AspNetUserLogins' has maximum length of 1800 bytes. For some combination of large values, the insert/update operation will fail.
Warning! The maximum key length for a clustered index is 900 bytes. The index 'PK_AspNetUserTokens' has maximum length of 1804 bytes. For some combination of large values, the insert/update operation will fail.
If ignoring this error, I would probably get in trouble later on with queries failing for "no apparent reason" (this reason).
My code is very straightforward:
internal class MintPlayerContext : IdentityDbContext<User, Role, int>
{
private readonly IConfiguration configuration;
public MintPlayerContext(IConfiguration configuration) : base()
{
this.configuration = configuration;
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
base.OnConfiguring(optionsBuilder);
optionsBuilder.UseSqlServer(configuration.GetConnectionString("MintPlayer"), options => options.MigrationsAssembly("MintPlayer.Data"));
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
}
}
internal class User : IdentityUser<int>
{
public string PictureUrl { get; set; }
}
internal class Role : IdentityRole<int>
{
}
I also tried using Guid's (I want to use Guids eventually) but even with int's MyLittleAdmin complaints about the Key being too long. I already checked on Google but this only gives diagnostic articles and does not really provide a solution.
Right now this is the AspNetUsers section of the migration:
CREATE TABLE [AspNetUsers] (
[Id] int NOT NULL IDENTITY,
[UserName] nvarchar(256) NULL,
[NormalizedUserName] nvarchar(256) NULL,
[Email] nvarchar(256) NULL,
[NormalizedEmail] nvarchar(256) NULL,
[EmailConfirmed] bit NOT NULL,
[PasswordHash] nvarchar(max) NULL,
[SecurityStamp] nvarchar(max) NULL,
[ConcurrencyStamp] nvarchar(max) NULL,
[PhoneNumber] nvarchar(max) NULL,
[PhoneNumberConfirmed] bit NOT NULL,
[TwoFactorEnabled] bit NOT NULL,
[LockoutEnd] datetimeoffset NULL,
[LockoutEnabled] bit NOT NULL,
[AccessFailedCount] int NOT NULL,
[PictureUrl] nvarchar(max) NULL,
CONSTRAINT [PK_AspNetUsers] PRIMARY KEY ([Id])
);
What can I do to solve this?
Edit:
I tried modifying my DbContext configuration to force the Key to be only the Id:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<User>().HasKey(u => u.Id);
modelBuilder.Entity<Role>().HasKey(r => r.Id);
}
This seems to affect the migration indeed:
[Id] int NOT NULL IDENTITY,
Instead of:
[Id] uniqueidentifier NOT NULL,
But it still gives the same error
Edit: Adding the AspNetUserLogins, AspNetUserRoles, stripped the if's
CREATE TABLE [AspNetUserLogins] (
[LoginProvider] nvarchar(450) NOT NULL,
[ProviderKey] nvarchar(450) NOT NULL,
[ProviderDisplayName] nvarchar(max) NULL,
[UserId] int NOT NULL,
CONSTRAINT [PK_AspNetUserLogins] PRIMARY KEY ([LoginProvider], [ProviderKey]),
CONSTRAINT [FK_AspNetUserLogins_AspNetUsers_UserId] FOREIGN KEY ([UserId]) REFERENCES [AspNetUsers] ([Id]) ON DELETE CASCADE
);
CREATE TABLE [AspNetUserTokens] (
[UserId] int NOT NULL,
[LoginProvider] nvarchar(450) NOT NULL,
[Name] nvarchar(450) NOT NULL,
[Value] nvarchar(max) NULL,
CONSTRAINT [PK_AspNetUserTokens] PRIMARY KEY ([UserId], [LoginProvider], [Name]),
CONSTRAINT [FK_AspNetUserTokens_AspNetUsers_UserId] FOREIGN KEY ([UserId]) REFERENCES [AspNetUsers] ([Id]) ON DELETE CASCADE
);
stringsomewhere as a primary key (since this will be used as the default clustered index by EF / SQL Server). Have a look for something like this :AspNetUserLogin : IdentityUserLogin<string>AspNetUserLoginsandAspNetUserTokens- you're not showing the definitions of those classes. I'm sure there's a string in there.nvarchar(450)already potentially takes up 900 bytes. It's a warning only - suggest you build your system with the external OAuth providers that you need (Facebook, Google, etc) and then check to see what the actual length of the strings really is and then reducing the widths. You could also consider dropping the unicode, i.e. make the columnsVARCHARif you don't find any non ASCII chars in these strings.