Причина, по которой я увидел ошибку, была связана с моей попыткой переопределить столбец, а не с заменой поля и предоставлением нового определения того, как я хотел, чтобы данные сохранялись в 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 вокруг таблиц.