Как настроить Identity Models для переименования столбцов и изменения размеров типов данных в IdentityServer4 - PullRequest
0 голосов
/ 17 мая 2018

Я играл с этим примером быстрого запуска и пытался понять, насколько далеко я могу настроить базу данных (у меня есть существующая база данных, которую я пытался реплицировать наполовину).

Я пробую свои силы в переименовании полей и переопределении типов данных, но столкнулся со следующей ошибкой:

InvalidOperationException: «Role.NormalisedName» и «Role.NormalizedName» сопоставлены со столбцом «NormalisedName» в «Roles», но настроены на использование разных типов данных («nvarchar (max)» и «nvarchar (256)»).

Сущность, которая настраивает IdentityRole в настоящее время выглядит следующим образом:

public class Role : IdentityRole<int>
{
    public int RoleId
    {
        get => base.Id;
        set => base.Id = value;
    }
    public string NormalisedName
    {
        get => base.NormalizedName;
        set => base.NormalizedName = value;
    }

    public ICollection<RoleClaim> ClaimsCollection { get; set; }
}

И переопределение в ApplicationDbContext выглядит так:

// "Microsoft.AspNetCore.Identity.IdentityRole"
ModelBuilder.Entity<Role>(E =>
{
    E.Property(P => P.Id)
        .HasColumnName("RoleId")
        .ValueGeneratedOnAdd();

    E.Property(P => P.ConcurrencyStamp)
        .HasMaxLength(512)
        .IsConcurrencyToken();

    E.Property(P => P.Name)
    .HasMaxLength(128);

    E.Property(P => P.NormalizedName)
        .HasMaxLength(128)
        .HasColumnName("NormalisedName");

    E.HasKey(P => P.Id);

    E.HasIndex(P => P.NormalizedName)
        .IsUnique()
        .HasName("IX_Roles_NormalisedName");

    E.ToTable("Roles");
});

Таблица «Роли» в базе данных имеет ширину nvarchar(512), установленную для столбцов Name и NormalisedName; это связано с индексом NormalisedName, который будет предупреждать о длине ключа в некластеризованном индексе, превышающем 1700 байт. Сгенерированное предупреждение будет выглядеть так:

Внимание! Максимальная длина ключа для некластеризованного индекса составляет 1700 байт. Индекс 'IX_Roles_NormalisedName' имеет максимальную длину 2048 байтов. Для некоторой комбинации больших значений операция вставки / обновления завершится неудачей.

Кто-нибудь знает, как (или даже если) я могу наложить этот предел на это поле? Указание только одного метода расширения HasMaxLength() не работает, как я ожидал.

1 Ответ

0 голосов
/ 17 мая 2018

Причина, по которой я увидел ошибку, была связана с моей попыткой переопределить столбец, а не с заменой поля и предоставлением нового определения того, как я хотел, чтобы данные сохранялись в SqlServer.

Поскольку я наложил свои правки на существующий материал в IdentityDbContext, ModelBuilder мог видеть оба поля и пытался немного склеить все вместе.

Лучшим примером переименования и удаления столбцов из объекта Identity будет IdentityUser, поэтому я буду использовать его в качестве примера, поскольку в нем есть больше вещей, которые я хотел бы изменить.

Макет объекта по умолчанию выглядит следующим образом:

public class IdentityUser<TKey> where TKey : IEquatable<TKey>
{
    public IdentityUser();
    public IdentityUser(string userName);
    public virtual DateTimeOffset? LockoutEnd { get; set; }
    public virtual bool TwoFactorEnabled { get; set; }
    public virtual bool PhoneNumberConfirmed { get; set; }
    public virtual string PhoneNumber { get; set; }
    public virtual string ConcurrencyStamp { get; set; }
    public virtual string SecurityStamp { get; set; }
    public virtual string PasswordHash { get; set; }
    public virtual bool EmailConfirmed { get; set; }
    public virtual string NormalizedEmail { get; set; }
    public virtual string Email { get; set; }
    public virtual string NormalizedUserName { get; set; }
    public virtual string UserName { get; set; }
    public virtual TKey Id { get; set; }
    public virtual bool LockoutEnabled { get; set; }
    public virtual int AccessFailedCount { get; set; }

    public override string ToString();
}

Скажем, мы работаем с базой данных в первую очередь, и я хочу внести различные изменения, например ...

  • сделать ключ Id целым числом (а столбец имеет атрибут «identity» в SqlServer)
  • переименовать таблицу
  • удалить поле LockoutEnd
  • удалить поле PhoneNumberConfirmed
  • удалить поле PhoneNumber
  • удалить поле LockoutEnabled
  • удалить поле AccessFailedCount
  • и переименуйте поля Id, NormalizedEmail и NormalizedUserName

Достаточно просто в теории, и на практике, если вы точно знаете, где искать ... Я на самом деле нашел ответ на этот вопрос случайно, пытаясь решить другую проблему. Итак, сверху.

Начиная с нового объекта "Пользователь", мне сначала нужно было убедиться, что тип ключа установлен.

public class User : IdentityUser<int>
{
}

В моем случае, поскольку я хотел переименовать поле, а также изменить тип, имело больше смысла полностью переопределить его; Id стал AccountId, чтобы сделать идентификатор одинаковым во всех моих таблицах.

public int AccountId { get; set; }

Затем выполняется резервное копирование в DbContext (в моем случае CustomerDbContext), здесь необходимо подтвердить изменение типа ключа, это было стандартное изменение наследования IdentityDbContext для указания типов, которые он должен использовать .

public partial class CustomerDbContext : IdentityDbContext<User, Role, int>
{
}

В этом и после base.OnModelCreating(ModelBuilder); мне нужно было определить ключ, который будет использоваться для этого объекта.

Мы можем также изменить имя таблицы, пока мы здесь.

protected override void OnModelCreating(ModelBuilder ModelBuilder)
{
    base.OnModelCreating(ModelBuilder);

    ModelBuilder.Entity<User>(Entity =>
    {
        Entity.HasKey(E => E.AccountId);

        Entity.ToTable("Users");
    });
}

Поле Id по-прежнему будет поднимать свою уродливую голову, но это будет отсортировано, когда мы удалим поля, которые нам не нужны из IdentityUser.

Чтобы переименовать поля NormalizedEmail и NormalizedUserName, вы можете просто указать для них имя столбца при построении объекта User, например: QL ( "(GETDATE ())");

Entity.Property(E => E.NormalizedEmail)
    .HasColumnName("NormalisedEmail")
    .IsRequired();

Entity.Property(E => E.NormalizedUserName)
    .HasColumnName("NormalisedUserName");

Красиво и просто, но вы не можете изменить определение столбца, насколько я могу судить, поэтому добавление .HasMaxLength(512) к любому из столбцов, например, приведет к ошибке (ширина столбца по умолчанию равна 450). Это на самом деле причина первого сообщения об ошибке в моем вопросе.

InvalidOperationException: 'Role.NormalisedName' и «Role.NormalizedName» отображаются в столбец «NormalisedName» в «Роли», но настроены на использование разных типов данных ('nvarchar (max)' и 'nvarchar (256)').

Мне было проще полностью переопределить поля; добавление

// I _think_ the original fields are used internally, so I
// couldn't dispense with them entirely.
public string NormalisedEmail
{
    get => NormalizedEmail;
    set => NormalizedEmail = value.ToLowerInvariant();
}
public string NormalisedUserName
{
    get => NormalizedUserName;
    set => NormalizedUserName = value.ToLowerInvariant();
}

в мой User класс и

Entity.Property(E => E.NormalisedEmail)
    .IsRequired()
    .HasMaxLength(512);

Entity.Property(E => E.NormalisedUserName)
    .HasMaxLength(512);

к моему Entity<User> определению в CustomerDbContext.

Наконец, удалить все неиспользуемые поля и оставшиеся поля Id, NormalizedEmail и NormalizedUserName, которые теперь переопределены; просто укажите, что они должны игнорироваться ModelBuilder, используя:

Entity.Ignore(E => E.Id)
    .Ignore(E => E.AccessFailedCount)
    .Ignore(E => E.LockoutEnabled)
    .Ignore(E => E.LockoutEnd)
    .Ignore(E => E.NormalizedEmail)
    .Ignore(E => E.NormalizedUserName)
    .Ignore(E => E.PhoneNumber)
    .Ignore(E => E.PhoneNumberConfirmed);

Этого было достаточно, чтобы я мог сначала спроектировать базу данных своего проекта, а затем согнуть Identity / IdentityServer вокруг таблиц.

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