我一直在玩this quickstart example&一直试图看我能在多大程度上自定义数据库(我有一个现有的数据库,我已经尝试复制了一半)。
我尝试重命名字段并重新定义数据类型但遇到以下错误:
InvalidOperationException异常: ' Role.NormalisedName'和' Role.NormalizedName'都被映射到列' NormalisedName'在'角色'但配置为使用不同的数据类型(' 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");
});
&#34;角色&#34;数据库中的表格nvarchar(512)
和Name
列的宽度均为NormalisedName
;这是由NormalisedName
上的索引引起的,该索引将警告非聚簇索引中的密钥长度超过1700字节。生成的警告将如下所示:
警告!非聚簇索引的最大密钥长度为1700字节。索引&#39; IX_Roles_NormalisedName&#39;最大长度为2048字节。对于某些大值组合,插入/更新操作将失败。
有没有人知道如何(或者甚至)我可以对此字段施加此限制?仅指定HasMaxLength()
扩展方法似乎并不像我预期的那样工作。
答案 0 :(得分:0)
我看到错误的原因是由于我尝试重新定义列,而不是替换字段并提供了我希望如何将数据存储在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
成为整数(并且该列在SqlServer中具有'identity'属性)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。