实体框架核心:无法在生产服务器上运行迁移脚本,聚集索引的最大密钥长度为 900 字节



我正在尝试将我的 ASP.NET Core网站部署在由Plesk托管的生产服务器上。我的解决方案中有 2 个项目:1 个包含我的DbContext,1 个包含我的 Web 项目。

我为我的DbContext生成了迁移:

dotnet ef migrations add AddIdentity --project ..MyProject.Data

然后我生成了一个生产迁移脚本,如文档 (https://learn.microsoft.com/en-us/ef/core/miscellaneous/cli/dotnet#dotnet-ef-migrations-script( 中所述

dotnet ef migrations script --idempotent --output "MigrationScriptsAddIdentity.sql" --context MyDbContext --project ..MyProject.Data

然后,我导航到生产服务器(MyLittleAdmin(上的SQL实用程序,并将生成的SQL脚本粘贴到其中。这成功了,但我收到以下错误:

警告!聚集索引的最大键长度为 900 字节。索引"PK_AspNetUserLogins"的最大长度为 1800 字节。对于大值的某种组合,插入/更新操作将失败。

警告!聚集索引的最大键长度为 900 字节。索引"PK_AspNetUserTokens"的最大长度为 1804 字节。对于大值的某种组合,插入/更新操作将失败。

如果忽略此错误,我以后可能会遇到麻烦,因为查询因"无明显原因"(此原因(而失败。

我的代码非常简单:

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的(我想最终使用Guids(,但即使int的MyLittleAdmin抱怨密钥太长。 我已经在谷歌上检查过,但这只提供了诊断文章,并没有真正提供解决方案。

现在,这是迁移的 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 配置以强制密钥仅为 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的

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
);

您可以尝试将其更改为:

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 个字符。我的意思是它只是一个名字。

所有列的总长度需要

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 将触发错误。 您可以尝试减少它。

AspNetUserLoginsAspNetUserTokens需要定义一个较短的键。我假设模型中没有定义键,因此所有列都添加到键中。也许包括一些大的字符串列。

谢谢大家,这是正确的。 感谢您的所有建议,我设法让它工作。

由于我使用的是代码优先,因此我不能只修改生成的迁移。 这就是我所做的:

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 "MigrationScriptsAddIdentity.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 可猜测。

最新更新