我正在基于现有的自定义数据库创建一个新的 IdentityDbContext。多年前就决定将自定义属性添加到另一个表 CustomUser 中,而不是向 AspNetUsers 添加自定义属性,以及它自己的标识列 UserId。然后 UserId 用作 CustomUserAccept 的外键,它记录用户何时接受服务条款、cookie 策略等。
public void CreateCustomUser(EntityTypeBuilder<CustomUser> entity)
{
entity
.ToTable("AspNetUsers")
.SplitToTable("CustomUser", CreateCustomUser);
entity.HasAlternateKey(e => e.UserId);
entity.HasMany(d => d.Accepts).WithMany()
.UsingEntity<CustomUserAccept>(
"CustomUserAccept",
r => r.HasOne(d => d.Accept).WithMany()
.HasForeignKey(d => d.AcceptId)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("FK_CustomUserAccept_AcceptId"),
l => l.HasOne(d => d.User).WithMany()
.HasPrincipalKey(d => d.UserId)
.HasForeignKey(d => d.UserId)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("FK_CustomUserAccept_UserId"),
CreateCustomUserAccept);
}
public void CreateCustomUser(SplitTableBuilder<CustomUser> entity)
{
entity.Property(e => e.UserId).UseIdentityColumn();
entity.Property(e => e.Id).HasColumnName("IdentityId");
entity.Property(e => e.CompanyId);
entity.Property(e => e.FirstName);
entity.Property(e => e.LastName);
entity.Property(e => e.LastLogonDate);
entity.Property(e => e.PasswordExpirationDate);
entity.Property(e => e.ChangePassword);
}
public void CreateCustomUserAccept(EntityTypeBuilder<CustomUserAccept> entity)
{
entity.HasKey(e => new { e.UserId, e.AcceptId });
entity.ToTable("CustomUserAccept");
entity.Property(e => e.CreatedDate)
.HasDefaultValueSql("(getutcdate())")
.HasColumnType("datetime");
}
我使用 Entity Splitting 将 AspNetUsers 和 SecureUser 合并到一个 SecureUser 模型中。它工作得很好......直到我添加了对 CustomAccept 的多对多引用。
“Microsoft.EntityFrameworkCore.Model.Validation.ForeignKeyPropertiesMappedToUnrelatedTables”:面向“CustomUser”的实体类型“CustomUserAccept (CustomUserAccept)”上的外键 {“UserId”} 无法在数据库中表示。属性 {'UserId'} 未映射到表 'CustomUserAccept',或者主要属性 {'UserId'} 未映射到表 'AspNetUsers'。所有外键属性必须映射到依赖类型映射到的表,并且所有主体属性必须映射到主体类型映射到的单个表。
是否有任何方法可以通过操作元数据或覆盖来解决“主要属性必须映射到单个表”的问题?除了放弃实体拆分之外,我还能做些什么吗?
我对其他想法持开放态度,但是当我翻转
CustomUser
到主表时,它起作用了,我能够登录。
public void CreateCustomUser(EntityTypeBuilder<CustomUser> entity)
{
entity
.ToTable("CustomUser")
.SplitToTable("AspNetUsers", CreateCustomUser);
entity.Property(e => e.Id).HasColumnName("IdentityId");
entity.HasAlternateKey(e => e.UserId);
entity.HasMany(d => d.Accepts).WithMany()
.UsingEntity<CustomUserAccept>(
"CustomUserAccept",
r => r.HasOne(d => d.Accept).WithMany()
.HasForeignKey(d => d.AcceptId)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("FK_CustomUserAccept_AcceptId"),
l => l.HasOne(d => d.User).WithMany()
.HasPrincipalKey(d => d.UserId)
.HasForeignKey(d => d.UserId)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("FK_CustomUserAccept_UserId"),
CreateCustomUserAccept);
}
public void CreateCustomUser(SplitTableBuilder<CustomUser> entity)
{
entity.Property(e => e.Id).HasColumnName("Id");
entity.Property(e => e.UserName);
entity.Property(e => e.NormalizedUserName);
entity.Property(e => e.Email);
entity.Property(e => e.NormalizedEmail);
entity.Property(e => e.EmailConfirmed);
entity.Property(e => e.PasswordHash);
entity.Property(e => e.SecurityStamp);
entity.Property(e => e.ConcurrencyStamp);
entity.Property(e => e.PhoneNumber);
entity.Property(e => e.PhoneNumberConfirmed);
entity.Property(e => e.TwoFactorEnabled);
entity.Property(e => e.LockoutEnd);
entity.Property(e => e.LockoutEnabled);
entity.Property(e => e.AccessFailedCount);
}