Я играл с этим примером быстрого запуска и пытался понять, насколько далеко я могу настроить базу данных (у меня есть существующая база данных, которую я пытался реплицировать наполовину).
Пока что мне повезло с возня с примером, легко добавить новые комбинации полей / столбцов; но теперь я хотел бы удалить поля по умолчанию из сущностей и связанные с ними столбцы из базы данных.
Итак, фокусируясь на объекте IdentityUser
, я настроил оригинал в ApplicationDbContext
, чтобы отразить, как бы я хотел, чтобы таблица выглядела. Исходное определение Я считаю следующим:
modelBuilder.Entity("IdentityServer4AspNetIdentity.Models.ApplicationUser", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("AccessFailedCount");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken();
b.Property<string>("Email")
.HasMaxLength(256);
b.Property<bool>("EmailConfirmed");
b.Property<bool>("LockoutEnabled");
b.Property<DateTimeOffset?>("LockoutEnd");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256);
b.Property<string>("NormalizedUserName")
.HasMaxLength(256);
b.Property<string>("PasswordHash");
b.Property<string>("PhoneNumber");
b.Property<bool>("PhoneNumberConfirmed");
b.Property<string>("SecurityStamp");
b.Property<bool>("TwoFactorEnabled");
b.Property<string>("UserName")
.HasMaxLength(256);
b.HasKey("Id");
b.HasIndex("NormalizedEmail")
.HasName("EmailIndex");
b.HasIndex("NormalizedUserName")
.IsUnique()
.HasName("UserNameIndex");
b.ToTable("AspNetUsers");
});
И мое переопределение определяет структуру следующим образом:
// "IdentityServer4AspNetIdentity.Models.ApplicationUser"
ModelBuilder.Entity<User>(E =>
{
E.Property(P => P.Id)
.HasColumnName("AccountId")
.ValueGeneratedOnAdd();
E.Property(P => P.ConcurrencyStamp)
.HasMaxLength(512)
.IsConcurrencyToken();
E.Property(P => P.Email)
.HasMaxLength(512)
.IsRequired();
E.Property(P => P.EmailConfirmed)
.ValueGeneratedOnAdd();
E.Property(P => P.NormalisedEmail)
.HasMaxLength(512)
.IsRequired();
E.Property(P => P.NormalisedUserName)
.HasMaxLength(256)
.IsRequired();
E.Property(P => P.PasswordHash);
E.Property(P => P.SecurityStamp)
.IsRequired();
E.Property(P => P.TwoFactorEnabled)
.ValueGeneratedOnAdd();
E.Property(P => P.UserName)
.HasMaxLength(256)
.IsRequired();
E.Property(P => P.Registered)
.ValueGeneratedOnAdd();
E.Property(P => P.LastVisit)
.IsRequired();
E.HasIndex(P => P.NormalisedEmail)
.HasName("IX_Users_NormalisedEmail");
E.HasIndex(P => P.NormalisedUserName)
.IsUnique()
.HasName("IX_Users_NormalisedUserName");
E.ToTable("Users");
});
Это переопределение соответствует этому User
объекту:
public class User : IdentityUser<int>
{
public int AccountId
{
get => base.Id;
set => base.Id = value;
}
public string NormalisedEmail
{
get => base.NormalizedEmail;
set => base.NormalizedEmail = value;
}
public string NormalisedUserName
{
get => base.NormalizedUserName;
set => base.NormalizedUserName = value;
}
public DateTime Registered { get; set; }
public DateTime LastVisit { get; set; }
public AccountDetail UserDetails { get; set; }
public AccountLockout Lockout { get; set; }
public PasswordReset PasswordResetRequested { get; set; }
public Concierge ConciergeAccountFlag { get; set; }
public NotValidated AccountValidatation { get; set; }
public ICollection<UserRole> AssignedRoles { get; set; }
public ICollection<UserClaim> ClaimsCollection { get; set; }
public ICollection<Login> Logins { get; set; }
public ICollection<LoginAttempt> LoginAttempts { get; set; }
public ICollection<Token> TokenCollection { get; set; }
}
Я подумал , что этого будет достаточно, чтобы переопределить объект и сохранить данные, которые я хотел, так, как я хотел, чтобы он был структурирован, однако я вижу следующее исключение при попытке войти в пример :
An unhandled exception occurred while processing the request.
SqlException: Invalid column name 'NormalizedUserName'.
Invalid column name 'AccessFailedCount'.
Invalid column name 'AccountValidatationAccountId'.
Invalid column name 'ConciergeAccountFlagAccountId'.
Invalid column name 'LockoutEnabled'.
Invalid column name 'LockoutEnd'.
Invalid column name 'NormalizedEmail'.
Invalid column name 'NormalizedUserName'.
Invalid column name 'PasswordResetRequestedAccountId'.
Invalid column name 'PhoneNumber'.
Invalid column name 'PhoneNumberConfirmed'.
Я знаю, что AccountValidatationAccountId
, ConciergeAccountFlagAccountId
и PasswordResetRequestedAccountId
- мои внешние ключи для сущностей "NotValidated", "Concierge" и "PasswordReset" (которые я скоро вставлю), но я потерян почему они включены в столбцы и почему они названы такими, какие они есть.
NotValidated:
ModelBuilder.Entity<NotValidated>(E =>
{
E.Property(P => P.AccountId)
.IsRequired()
.ValueGeneratedNever();
E.Property(P => P.ValidationKey)
.IsRequired()
.HasMaxLength(128)
.ValueGeneratedNever();
E.Property(P => P.Expires)
.IsRequired()
.ValueGeneratedOnAddOrUpdate();
E.HasKey(P => P.AccountId);
E.HasOne(P => P.Account)
.WithOne()
.HasForeignKey<User>(P => P.AccountId)
.OnDelete(DeleteBehavior.Cascade)
.HasConstraintName("FK_NotValidated_Users_AccountId");
E.ToTable("NotValidated");
});
public class NotValidated
{
public int AccountId { get; set; }
public string ValidationKey { get; set; }
public DateTime Expires { get; set; }
public User Account { get; set; }
}
Консьерж:
ModelBuilder.Entity<Concierge>(E =>
{
E.Property(P => P.AccountId)
.IsRequired()
.ValueGeneratedNever();
E.HasKey(P => P.AccountId);
E.HasOne(P => P.Account)
.WithOne()
.HasForeignKey<User>(P => P.AccountId)
.OnDelete(DeleteBehavior.Cascade)
.HasConstraintName("FK_Concierge_Users_AccountId");
E.ToTable("ConciergeMap");
});
public class Concierge
{
public int AccountId { get; set; }
public User Account { get; set; }
}
И, наконец, сброс пароля:
ModelBuilder.Entity<PasswordReset>(E =>
{
E.Property(P => P.AccountId)
.IsRequired()
.ValueGeneratedNever();
E.Property(P => P.OneTimeKey)
.IsRequired()
.HasMaxLength(128)
.ValueGeneratedNever();
E.Property(P => P.Expires)
.IsRequired()
.ValueGeneratedNever();
E.HasKey(P => P.AccountId);
E.HasOne(P => P.Account)
.WithOne()
.HasForeignKey<User>(P => P.AccountId)
.OnDelete(DeleteBehavior.Cascade)
.HasConstraintName("FK_PasswordReset_Users_AccountId");
E.ToTable("PasswordReset");
});
public class PasswordReset
{
public int AccountId { get; set; }
public string OneTimeKey { get; set; }
public DateTime Expires { get; set; }
public User Account { get; set; }
}
Мне удалось немного сократить список, пытаясь не реализовать поля, которые мне не нужны, что приводит к ошибке ниже:
An unhandled exception occurred while processing the request.
SqlException: Invalid column name 'NormalizedUserName'.
Invalid column name 'AccountValidatationAccountId'.
Invalid column name 'ConciergeAccountFlagAccountId'.
Invalid column name 'NormalizedEmail'.
Invalid column name 'NormalizedUserName'.
Invalid column name 'PasswordResetRequestedAccountId'.
Я сделал это, добавив следующие строки кода в конец класса Users
, но я думаю, что это отвратительно и определенно не должно быть подходом для этого:
public new int AccessFailedCount => throw new NotImplementedException();
public new int Id => throw new NotImplementedException("Use 'AccountId'.");
public new bool LockoutEnabled => throw new NotImplementedException();
public new DateTimeOffset? LockoutEnd => throw new NotImplementedException();
public new string NormalizedEmail => throw new NotImplementedException(
"Use 'NormalisedEmail'."
);
public new string NormalizedUserName => throw new NotImplementedException(
"Use 'NormalisedUserName'."
);
public new string PhoneNumber => throw new NotImplementedException();
public new bool PhoneNumberConfirmed => throw new NotImplementedException();
У кого-нибудь есть указания, где я ошибаюсь при указании и хранении своих полей? Любые идеи о том, почему эти столбцы внешнего ключа добавляются, также приветствуются.