1

我正在尝试将我的 ASP.NET Core 网站部署在由 Plesk 托管的生产服务器上。我的解决方案中有 2 个项目:1 个包含 my 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 脚本粘贴到其中。这成功,但我收到以下错误:

警告!聚集索引的最大键长度为 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(我最终想使用 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 的

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

3 回答 3

3

您可以尝试将其更改为:

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

于 2019-12-27T09:09:55.503 回答
1

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

于 2019-12-27T08:06:53.783 回答
0

谢谢大家,很到位。感谢您的所有建议,我设法让它工作。

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

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,以免 UserIds 被猜测。

于 2019-12-27T09:48:38.367 回答