Индекс удаления отката миграций EF Core несколько раз - PullRequest
0 голосов
/ 07 октября 2019

У меня есть таблица Users для приложения, которое всегда использовало строго Windows Authentication. Из-за этого в нем есть WindowsSid столбец для SID пользователя его учетной записи. Таблица в том виде, как она есть, создается следующим образом:

CREATE TABLE [dbo].[User](
[UserId] [uniqueidentifier] ROWGUIDCOL  NOT NULL,
[WindowsSid] [varbinary](85) NOT NULL,
[UserName] [nvarchar](255) NOT NULL,
CONSTRAINT [PK_User] PRIMARY KEY NONCLUSTERED 
(
    [UserId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY],
CONSTRAINT [Unique_User_WindowsSid] UNIQUE NONCLUSTERED 
(

    [WindowsSid] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

ALTER TABLE [dbo].[User] ADD  CONSTRAINT [Default_User_UserID]  DEFAULT (newid()) FOR [UserId]
GO

Теперь мы добавляем поддержку Azure Active Directory. Для этого я добавил в таблицу столбец, который будет использовать идентификатор объекта Azure пользователя вместо его SID. Поскольку у этих пользователей не будет SID, мне нужно изменить таблицу, чтобы пустые значения в столбце WindowsSid. DbContext теперь выглядит следующим образом:

            entity.HasIndex(e => e.WindowsSid)
                .HasName("Unique_User_WindowsSid")
                .IsUnique();

            entity.HasIndex(e => e.AzureAdObjectId)
                .HasName("IX_Unique_User_AzureAdObjectId")
                .IsUnique();

            entity.Property(e => e.WindowsSid)
                .IsRequired(false)
                .HasMaxLength(85);

Единственное отличие от исходной конфигурации заключается в добавлении уникального индекса AzureObjectId и изменении IsRequired() для WindowsSid на IsRequired(false).

Это привело к следующей миграции:

protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropUniqueConstraint(
    name: "Unique_User_WindowsSid",
    table: "User");

migrationBuilder.AlterColumn<byte[]>(
    name: "WindowsSid",
    table: "User",
    maxLength: 85,
    nullable: true,
    oldClrType: typeof(byte[]),
    oldMaxLength: 85);

migrationBuilder.AddColumn<Guid>(
    name: "AzureAdObjectId",
    table: "User",
    nullable: true);

migrationBuilder.CreateIndex(
    name: "IX_Unique_User_AzureAdObjectId",
    table: "User",
    column: "AzureAdObjectId",
    unique: true,
    filter: "[AzureAdObjectId] IS NOT NULL");

migrationBuilder.CreateIndex(
    name: "Unique_User_WindowsSid",
    table: "User",
    column: "WindowsSid",
    unique: true,
    filter: "[WindowsSid] IS NOT NULL");
}

protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropIndex(
    name: "IX_Unique_User_AzureAdObjectId",
    table: "User");

migrationBuilder.DropIndex(
    name: "Unique_User_WindowsSid",
    table: "User");

migrationBuilder.DropColumn(
    name: "AzureAdObjectId",
    table: "User");

migrationBuilder.AlterColumn<byte[]>(
    name: "WindowsSid",
    table: "User",
    maxLength: 85,
    nullable: false,
    oldClrType: typeof(byte[]),
    oldMaxLength: 85,
    oldNullable: true);

migrationBuilder.AddUniqueConstraint(
    name: "Unique_User_WindowsSid",
    table: "User",
    column: "WindowsSid");
}

Обновление базы данных таким способом работает нормально, однако у меня возникла проблема при ее откате с использованием метода Down(). Когда я пытаюсь выполнить откат, я получаю эту ошибку:

Cannot drop the index 'User.Unique_User_WindowsSid', because it does not exist or you do not have permission.

Я исследовал с помощью сценариев фактический SQL, который выполняется при откате, и он выдал следующее:

DROP INDEX [IX_Unique_User_AzureAdObjectId] ON [User];

GO

DROP INDEX [Unique_User_WindowsSid] ON [User];

GO

DECLARE @var0 sysname;
SELECT @var0 = [d].[name]
FROM [sys].[default_constraints] [d]
INNER JOIN [sys].[columns] [c] ON [d].[parent_column_id] = [c].[column_id] AND [d].[parent_object_id] = [c].[object_id]
WHERE ([d].[parent_object_id] = OBJECT_ID(N'[User]') AND [c].[name] = N'AzureAdObjectId');
IF @var0 IS NOT NULL EXEC(N'ALTER TABLE [User] DROP CONSTRAINT [' + @var0 + '];');
ALTER TABLE [User] DROP COLUMN [AzureAdObjectId];

GO

DROP INDEX [Unique_User_WindowsSid] ON [User];
DECLARE @var1 sysname;
SELECT @var1 = [d].[name]
FROM [sys].[default_constraints] [d]
INNER JOIN [sys].[columns] [c] ON [d].[parent_column_id] = [c].[column_id] AND [d].[parent_object_id] = [c].[object_id]
WHERE ([d].[parent_object_id] = OBJECT_ID(N'[User]') AND [c].[name] = N'WindowsSid');
IF @var1 IS NOT NULL EXEC(N'ALTER TABLE [User] DROP CONSTRAINT [' + @var1 + '];');
ALTER TABLE [User] ALTER COLUMN [WindowsSid] varbinary(85) NOT NULL;
CREATE UNIQUE INDEX [Unique_User_WindowsSid] ON [User] ([WindowsSid]);

GO

ALTER TABLE [User] ADD CONSTRAINT [Unique_User_WindowsSid] UNIQUE ([WindowsSid]);

GO

DELETE FROM [__EFMigrationsHistory]
WHERE [MigrationId] = N'20191007182257_MigrationName';

GO

При ближайшем рассмотрении, он работает DROP INDEX [Unique_User_WindowsSid] ON [User] дважды . Один раз, когда это явно предполагается, и снова при переводе метода AlterColumn(). Я полагаю, что мог бы пойти и удалить первый DropColumn(), который был сгенерирован, чтобы заставить его работать, но мне любопытно, что я мог сделать здесь неправильно, чтобы заставить EF Core генерировать откат, который на самом деле не работает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...