Entity Framework 核心:无法在生产服务器上 运行 迁移脚本,聚簇索引的最大键长度为 900 字节
Entity Framework Core: Unable to run migration script on production server, The maximum key length for a clustered index is 900 bytes
我正在尝试在使用 Plesk 托管的生产服务器上部署我的 ASP.NET 核心网站。我的解决方案中有 2 个项目:1 个包含我的 DbContext
,1 个包含我的 Web 项目。
我为我的DbContext
生成了迁移:
dotnet ef migrations add AddIdentity --project ..\MyProject.Data
然后我生成了文档中提到的生产迁移脚本 (https://docs.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
然后我导航到生产服务器 (MyLittleAdmin) 上的 SQL 实用程序,并将生成的 SQL 脚本粘贴到其中。这成功了,但我收到以下错误:
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.
如果忽略这个错误,我以后可能会因为 "no apparent reason"(这个原因)的查询失败而遇到麻烦。
我的代码非常简单:
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>
{
}
我也尝试过使用 Guid(我最终想使用 Guid),但即使 int 的 MyLittleAdmin 抱怨密钥太长。
我已经检查过 Google 但这只提供诊断文章,并没有真正提供解决方案。
现在这是迁移的 AspNetUsers 部分:
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])
);
我该怎么做才能解决这个问题?
编辑:
我尝试修改我的 DbContext 配置以强制 Key 仅为 Id:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<User>().HasKey(u => u.Id);
modelBuilder.Entity<Role>().HasKey(r => r.Id);
}
这似乎确实影响了迁移:
[Id] int NOT NULL IDENTITY,
而不是:
[Id] uniqueidentifier NOT NULL,
但是还是报同样的错误
编辑:添加 AspNetUserLogins、AspNetUserRoles,删除 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
);
AspNetUserLogins
和 AspNetUserTokens
需要定义一个较短的键。我假设模型中没有定义任何键,因此所有列都添加到键中。可能包括一些大字符串列。
你可以试试改成:
CREATE TABLE [AspNetUserTokens] (
[UserId] int NOT NULL,
[LoginProvider] nvarchar(150) NOT NULL,
[Name] nvarchar(150) NOT NULL,
[Value] nvarchar(150) NULL,
CONSTRAINT [PK_AspNetUserTokens] PRIMARY KEY ([UserId], [LoginProvider], [Name]),
CONSTRAINT [FK_AspNetUserTokens_AspNetUsers_UserId] FOREIGN KEY ([UserId]) REFERENCES [AspNetUsers] ([Id]) ON DELETE CASCADE
);
我认为名称不能超过 150 个字符。我的意思是它只是一个名字。
所有列的总长度需要小于 900。
ALTER TABLE sampleTable ALTER COLUMN column1 VARCHAR (400) NULL;
ALTER TABLE sampleTable ALTER COLUMN column2 VARCHAR (200) NULL;
ALTER TABLE sampleTable ALTER COLUMN column3 VARCHAR (200) NULL;
根据评论,您应该尝试外部 Oauth 提供并得出一个合理的数字。
另外,nvarchar的存储大小是*2。 450 * 2 将触发错误。你可以试着减少它。
谢谢大家,很到位。
感谢您的所有建议,我设法使其正常工作。
因为我使用的是代码优先,所以我不能只修改我生成的迁移。
这就是我所做的:
internal class MintPlayerContext : IdentityDbContext<User, Role, int>
{
// dotnet ef migrations add AddIdentity --project ..\MyProject.Data
// dotnet ef database update --project ..\MyProject.Data
// (only looks at your appsettings.json file, not your appsettings.*.json, so for local development)
// To generate production migrations
// dotnet ef migrations script --idempotent --output "MigrationScripts\AddIdentity.sql" --context MyDbContext --project ..\MyProject.Data
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("MyProject"), options => options.MigrationsAssembly("MyProject.Data"));
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Microsoft.AspNetCore.Identity.IdentityUserLogin<int>>()
.Property(ut => ut.LoginProvider)
.HasMaxLength(50);
modelBuilder.Entity<Microsoft.AspNetCore.Identity.IdentityUserLogin<int>>()
.Property(ut => ut.ProviderKey)
.HasMaxLength(200);
modelBuilder.Entity<Microsoft.AspNetCore.Identity.IdentityUserToken<int>>()
.Property(ut => ut.LoginProvider)
.HasMaxLength(50);
modelBuilder.Entity<Microsoft.AspNetCore.Identity.IdentityUserToken<int>>()
.Property(ut => ut.Name)
.HasMaxLength(50);
}
}
我将使用 Guid,以免让 UserId 变得可猜测。
我正在尝试在使用 Plesk 托管的生产服务器上部署我的 ASP.NET 核心网站。我的解决方案中有 2 个项目:1 个包含我的 DbContext
,1 个包含我的 Web 项目。
我为我的DbContext
生成了迁移:
dotnet ef migrations add AddIdentity --project ..\MyProject.Data
然后我生成了文档中提到的生产迁移脚本 (https://docs.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
然后我导航到生产服务器 (MyLittleAdmin) 上的 SQL 实用程序,并将生成的 SQL 脚本粘贴到其中。这成功了,但我收到以下错误:
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.
如果忽略这个错误,我以后可能会因为 "no apparent reason"(这个原因)的查询失败而遇到麻烦。
我的代码非常简单:
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>
{
}
我也尝试过使用 Guid(我最终想使用 Guid),但即使 int 的 MyLittleAdmin 抱怨密钥太长。 我已经检查过 Google 但这只提供诊断文章,并没有真正提供解决方案。
现在这是迁移的 AspNetUsers 部分:
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])
);
我该怎么做才能解决这个问题?
编辑:
我尝试修改我的 DbContext 配置以强制 Key 仅为 Id:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<User>().HasKey(u => u.Id);
modelBuilder.Entity<Role>().HasKey(r => r.Id);
}
这似乎确实影响了迁移:
[Id] int NOT NULL IDENTITY,
而不是:
[Id] uniqueidentifier NOT NULL,
但是还是报同样的错误
编辑:添加 AspNetUserLogins、AspNetUserRoles,删除 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
);
AspNetUserLogins
和 AspNetUserTokens
需要定义一个较短的键。我假设模型中没有定义任何键,因此所有列都添加到键中。可能包括一些大字符串列。
你可以试试改成:
CREATE TABLE [AspNetUserTokens] (
[UserId] int NOT NULL,
[LoginProvider] nvarchar(150) NOT NULL,
[Name] nvarchar(150) NOT NULL,
[Value] nvarchar(150) NULL,
CONSTRAINT [PK_AspNetUserTokens] PRIMARY KEY ([UserId], [LoginProvider], [Name]),
CONSTRAINT [FK_AspNetUserTokens_AspNetUsers_UserId] FOREIGN KEY ([UserId]) REFERENCES [AspNetUsers] ([Id]) ON DELETE CASCADE
);
我认为名称不能超过 150 个字符。我的意思是它只是一个名字。
所有列的总长度需要小于 900。
ALTER TABLE sampleTable ALTER COLUMN column1 VARCHAR (400) NULL;
ALTER TABLE sampleTable ALTER COLUMN column2 VARCHAR (200) NULL;
ALTER TABLE sampleTable ALTER COLUMN column3 VARCHAR (200) NULL;
根据评论,您应该尝试外部 Oauth 提供并得出一个合理的数字。
另外,nvarchar的存储大小是*2。 450 * 2 将触发错误。你可以试着减少它。
谢谢大家,很到位。 感谢您的所有建议,我设法使其正常工作。
因为我使用的是代码优先,所以我不能只修改我生成的迁移。 这就是我所做的:
internal class MintPlayerContext : IdentityDbContext<User, Role, int>
{
// dotnet ef migrations add AddIdentity --project ..\MyProject.Data
// dotnet ef database update --project ..\MyProject.Data
// (only looks at your appsettings.json file, not your appsettings.*.json, so for local development)
// To generate production migrations
// dotnet ef migrations script --idempotent --output "MigrationScripts\AddIdentity.sql" --context MyDbContext --project ..\MyProject.Data
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("MyProject"), options => options.MigrationsAssembly("MyProject.Data"));
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Microsoft.AspNetCore.Identity.IdentityUserLogin<int>>()
.Property(ut => ut.LoginProvider)
.HasMaxLength(50);
modelBuilder.Entity<Microsoft.AspNetCore.Identity.IdentityUserLogin<int>>()
.Property(ut => ut.ProviderKey)
.HasMaxLength(200);
modelBuilder.Entity<Microsoft.AspNetCore.Identity.IdentityUserToken<int>>()
.Property(ut => ut.LoginProvider)
.HasMaxLength(50);
modelBuilder.Entity<Microsoft.AspNetCore.Identity.IdentityUserToken<int>>()
.Property(ut => ut.Name)
.HasMaxLength(50);
}
}
我将使用 Guid,以免让 UserId 变得可猜测。