Entity Framework Core 3.1 将 IdentityDbContext 与 myDbContext 合并
Entity Framework Core 3.1 merge IdentityDbContext with myDbContext
我想将默认标识 DbContext
与其他表(我自己的 DbContext
)合并;我对身份 DbContext
进行了逆向工程:它提供了模型 classes(有些模型是部分模型)和一个 DbContext
:
namespace pakshavad.Data
{
public partial class aspnetpakshavadContext : DbContext
{
public aspnetpakshavadContext()
{
}
public aspnetpakshavadContext(DbContextOptions<aspnetpakshavadContext> options)
: base(options)
{
}
public virtual DbSet<AspNetRoleClaims> AspNetRoleClaims { get; set; }
public virtual DbSet<AspNetRoles> AspNetRoles { get; set; }
public virtual DbSet<AspNetUserClaims> AspNetUserClaims { get; set; }
public virtual DbSet<AspNetUserLogins> AspNetUserLogins { get; set; }
public virtual DbSet<AspNetUserRoles> AspNetUserRoles { get; set; }
public virtual DbSet<AspNetUserTokens> AspNetUserTokens { get; set; }
public virtual DbSet<AspNetUsers> AspNetUsers { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
#warning To protect potentially sensitive information in your connection string, you should move it out of source code. See http://go.microsoft.com/fwlink/?LinkId=723263 for guidance on storing connection strings.
optionsBuilder.UseSqlServer("Server=.\MSSQLSERVER2017;Database=aspnet-pakshavad;Trusted_Connection=True;MultipleActiveResultSets=true");
}
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<AspNetRoleClaims>(entity =>
{
entity.HasIndex(e => e.RoleId);
entity.Property(e => e.RoleId).IsRequired();
entity.HasOne(d => d.Role)
.WithMany(p => p.AspNetRoleClaims)
.HasForeignKey(d => d.RoleId);
});
modelBuilder.Entity<AspNetRoles>(entity =>
{
entity.HasIndex(e => e.NormalizedName)
.HasName("RoleNameIndex")
.IsUnique()
.HasFilter("([NormalizedName] IS NOT NULL)");
entity.Property(e => e.Name).HasMaxLength(256);
entity.Property(e => e.NormalizedName).HasMaxLength(256);
});
modelBuilder.Entity<AspNetUserClaims>(entity =>
{
entity.HasIndex(e => e.UserId);
entity.Property(e => e.UserId).IsRequired();
entity.HasOne(d => d.User)
.WithMany(p => p.AspNetUserClaims)
.HasForeignKey(d => d.UserId);
});
modelBuilder.Entity<AspNetUserLogins>(entity =>
{
entity.HasKey(e => new { e.LoginProvider, e.ProviderKey });
entity.HasIndex(e => e.UserId);
entity.Property(e => e.LoginProvider).HasMaxLength(128);
entity.Property(e => e.ProviderKey).HasMaxLength(128);
entity.Property(e => e.UserId).IsRequired();
entity.HasOne(d => d.User)
.WithMany(p => p.AspNetUserLogins)
.HasForeignKey(d => d.UserId);
});
modelBuilder.Entity<AspNetUserRoles>(entity =>
{
entity.HasKey(e => new { e.UserId, e.RoleId });
entity.HasIndex(e => e.RoleId);
entity.HasOne(d => d.Role)
.WithMany(p => p.AspNetUserRoles)
.HasForeignKey(d => d.RoleId);
entity.HasOne(d => d.User)
.WithMany(p => p.AspNetUserRoles)
.HasForeignKey(d => d.UserId);
});
modelBuilder.Entity<AspNetUserTokens>(entity =>
{
entity.HasKey(e => new { e.UserId, e.LoginProvider, e.Name });
entity.Property(e => e.LoginProvider).HasMaxLength(128);
entity.Property(e => e.Name).HasMaxLength(128);
entity.HasOne(d => d.User)
.WithMany(p => p.AspNetUserTokens)
.HasForeignKey(d => d.UserId);
});
modelBuilder.Entity<AspNetUsers>(entity =>
{
entity.HasIndex(e => e.NormalizedEmail)
.HasName("EmailIndex");
entity.HasIndex(e => e.NormalizedUserName)
.HasName("UserNameIndex")
.IsUnique()
.HasFilter("([NormalizedUserName] IS NOT NULL)");
entity.Property(e => e.Email).HasMaxLength(256);
entity.Property(e => e.NormalizedEmail).HasMaxLength(256);
entity.Property(e => e.NormalizedUserName).HasMaxLength(256);
entity.Property(e => e.UserName).HasMaxLength(256);
});
OnModelCreatingPartial(modelBuilder);
}
partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
}
}
我将这些 class 复制到了我的项目中。例如:
namespace Domain.Models.Identity
{
public partial class AspNetUser : BaseEntity
{
public AspNetUser()
{
AspNetUserClaims = new HashSet<AspNetUserClaim>();
AspNetUserLogins = new HashSet<AspNetUserLogin>();
AspNetUserRoles = new HashSet<AspNetUserRole>();
AspNetUserTokens = new HashSet<AspNetUserToken>();
}
public string UserName { get; set; }
public string NormalizedUserName { get; set; }
public string Email { get; set; }
public string NormalizedEmail { get; set; }
public bool EmailConfirmed { get; set; }
public string PasswordHash { get; set; }
public string SecurityStamp { get; set; }
public string ConcurrencyStamp { get; set; }
public string PhoneNumber { get; set; }
public bool PhoneNumberConfirmed { get; set; }
public bool TwoFactorEnabled { get; set; }
public DateTimeOffset? LockoutEnd { get; set; }
public bool LockoutEnabled { get; set; }
public int AccessFailedCount { get; set; }
public virtual ICollection<AspNetUserClaim> AspNetUserClaims { get; set; }
public virtual ICollection<AspNetUserLogin> AspNetUserLogins { get; set; }
public virtual ICollection<AspNetUserRole> AspNetUserRoles { get; set; }
public virtual ICollection<AspNetUserToken> AspNetUserTokens { get; set; }
}
public partial class AspNetUserConfigure : IEntityTypeConfiguration<AspNetUser>
{
public void Configure(EntityTypeBuilder<AspNetUser> builder)
{
builder.HasIndex(e => e.NormalizedEmail)
.HasName("EmailIndex");
builder.HasIndex(e => e.NormalizedUserName)
.HasName("UserNameIndex")
.IsUnique()
.HasFilter("([NormalizedUserName] IS NOT NULL)");
builder.Property(e => e.Email).HasMaxLength(256);
builder.Property(e => e.NormalizedEmail).HasMaxLength(256);
builder.Property(e => e.NormalizedUserName).HasMaxLength(256);
builder.Property(e => e.UserName).HasMaxLength(256);
}
}
}
和 MyDbContext
(在另一个 class 库中),在我的项目中,我使用反射和 IEntityTypeConfiguration
自动创建 DbSets 的接口:
public class ApplicationDbContext : IdentityDbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
var entitiesAssembly = typeof(IEntity).Assembly;
modelBuilder.RegisterAllEntities<IEntity>(entitiesAssembly);
modelBuilder.RegisterEntityTypeConfiguration(entitiesAssembly);
modelBuilder.AddRestrictDeleteBehaviorConvention();
modelBuilder.AddSequentialGuidForIdConvention();
modelBuilder.AddPluralizingTableNameConvention();
OnModelCreatingPartial(modelBuilder);
}
partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
}
但是
partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
方法,我得到一个错误:
A partial method must be declared within a partial class, partial struct, or partial interface
我不知道如何解决这个错误。有人可以帮我吗?
第二个问题:我的 DbContext
是否需要从 IdentityDbContext
class 继承?
既然你问的是你是否应该从 IdentityDbContext
继承你的 class,我的回答将是一个响亮的是的 。通过这样做,您将不必反编译库代码并自己支持它。 Microsoft 和社区为您维护它做得很好 - 节省您的时间。因此,这也有望解决您的第一个问题。
据我所知,您已经从库存标准库中复制了所有 DbSet
属性和大部分 AspNetUserConfigure
。对于这个答案,我假设您想覆盖某些行为并将 .HasFilter("([NormalizedUserName] IS NOT NULL)")
添加到您的 AspNetUser
.
public class aspnetpakshavadContext: IdentityDbContext {
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("your-connection-string"); // you will notice I removed .IsConfigured check - I believe this is redundant as OnConfiguring should always have it set to `false`
}
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(builder); // this is calling all relevant code from IdentityDbContext that you have previously copied. Yours will go afterwards to ensure your changes are applied last
modelBuilder.ApplyConfiguration(new MyAspNetUserConfiguration());// your extension point to modify particular entity model
}
public class MyAspNetUserConfiguration: IEntityTypeConfiguration<PortalUser>
{
public void Configure(EntityTypeBuilder<AspNetUser> builder)
{
builder.HasFilter("([NormalizedUserName] IS NOT NULL)"); // Builders are chained, so as long as you've called this after base method `OnModelCreating` above - this should add to existing model.
}
}
}
希望这就是您所追求的。
附带说明一下,我不确定您的部分实现来自哪里,因为 IdentityDbContext
的原始代码似乎没有任何...
我想将默认标识 DbContext
与其他表(我自己的 DbContext
)合并;我对身份 DbContext
进行了逆向工程:它提供了模型 classes(有些模型是部分模型)和一个 DbContext
:
namespace pakshavad.Data
{
public partial class aspnetpakshavadContext : DbContext
{
public aspnetpakshavadContext()
{
}
public aspnetpakshavadContext(DbContextOptions<aspnetpakshavadContext> options)
: base(options)
{
}
public virtual DbSet<AspNetRoleClaims> AspNetRoleClaims { get; set; }
public virtual DbSet<AspNetRoles> AspNetRoles { get; set; }
public virtual DbSet<AspNetUserClaims> AspNetUserClaims { get; set; }
public virtual DbSet<AspNetUserLogins> AspNetUserLogins { get; set; }
public virtual DbSet<AspNetUserRoles> AspNetUserRoles { get; set; }
public virtual DbSet<AspNetUserTokens> AspNetUserTokens { get; set; }
public virtual DbSet<AspNetUsers> AspNetUsers { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
#warning To protect potentially sensitive information in your connection string, you should move it out of source code. See http://go.microsoft.com/fwlink/?LinkId=723263 for guidance on storing connection strings.
optionsBuilder.UseSqlServer("Server=.\MSSQLSERVER2017;Database=aspnet-pakshavad;Trusted_Connection=True;MultipleActiveResultSets=true");
}
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<AspNetRoleClaims>(entity =>
{
entity.HasIndex(e => e.RoleId);
entity.Property(e => e.RoleId).IsRequired();
entity.HasOne(d => d.Role)
.WithMany(p => p.AspNetRoleClaims)
.HasForeignKey(d => d.RoleId);
});
modelBuilder.Entity<AspNetRoles>(entity =>
{
entity.HasIndex(e => e.NormalizedName)
.HasName("RoleNameIndex")
.IsUnique()
.HasFilter("([NormalizedName] IS NOT NULL)");
entity.Property(e => e.Name).HasMaxLength(256);
entity.Property(e => e.NormalizedName).HasMaxLength(256);
});
modelBuilder.Entity<AspNetUserClaims>(entity =>
{
entity.HasIndex(e => e.UserId);
entity.Property(e => e.UserId).IsRequired();
entity.HasOne(d => d.User)
.WithMany(p => p.AspNetUserClaims)
.HasForeignKey(d => d.UserId);
});
modelBuilder.Entity<AspNetUserLogins>(entity =>
{
entity.HasKey(e => new { e.LoginProvider, e.ProviderKey });
entity.HasIndex(e => e.UserId);
entity.Property(e => e.LoginProvider).HasMaxLength(128);
entity.Property(e => e.ProviderKey).HasMaxLength(128);
entity.Property(e => e.UserId).IsRequired();
entity.HasOne(d => d.User)
.WithMany(p => p.AspNetUserLogins)
.HasForeignKey(d => d.UserId);
});
modelBuilder.Entity<AspNetUserRoles>(entity =>
{
entity.HasKey(e => new { e.UserId, e.RoleId });
entity.HasIndex(e => e.RoleId);
entity.HasOne(d => d.Role)
.WithMany(p => p.AspNetUserRoles)
.HasForeignKey(d => d.RoleId);
entity.HasOne(d => d.User)
.WithMany(p => p.AspNetUserRoles)
.HasForeignKey(d => d.UserId);
});
modelBuilder.Entity<AspNetUserTokens>(entity =>
{
entity.HasKey(e => new { e.UserId, e.LoginProvider, e.Name });
entity.Property(e => e.LoginProvider).HasMaxLength(128);
entity.Property(e => e.Name).HasMaxLength(128);
entity.HasOne(d => d.User)
.WithMany(p => p.AspNetUserTokens)
.HasForeignKey(d => d.UserId);
});
modelBuilder.Entity<AspNetUsers>(entity =>
{
entity.HasIndex(e => e.NormalizedEmail)
.HasName("EmailIndex");
entity.HasIndex(e => e.NormalizedUserName)
.HasName("UserNameIndex")
.IsUnique()
.HasFilter("([NormalizedUserName] IS NOT NULL)");
entity.Property(e => e.Email).HasMaxLength(256);
entity.Property(e => e.NormalizedEmail).HasMaxLength(256);
entity.Property(e => e.NormalizedUserName).HasMaxLength(256);
entity.Property(e => e.UserName).HasMaxLength(256);
});
OnModelCreatingPartial(modelBuilder);
}
partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
}
}
我将这些 class 复制到了我的项目中。例如:
namespace Domain.Models.Identity
{
public partial class AspNetUser : BaseEntity
{
public AspNetUser()
{
AspNetUserClaims = new HashSet<AspNetUserClaim>();
AspNetUserLogins = new HashSet<AspNetUserLogin>();
AspNetUserRoles = new HashSet<AspNetUserRole>();
AspNetUserTokens = new HashSet<AspNetUserToken>();
}
public string UserName { get; set; }
public string NormalizedUserName { get; set; }
public string Email { get; set; }
public string NormalizedEmail { get; set; }
public bool EmailConfirmed { get; set; }
public string PasswordHash { get; set; }
public string SecurityStamp { get; set; }
public string ConcurrencyStamp { get; set; }
public string PhoneNumber { get; set; }
public bool PhoneNumberConfirmed { get; set; }
public bool TwoFactorEnabled { get; set; }
public DateTimeOffset? LockoutEnd { get; set; }
public bool LockoutEnabled { get; set; }
public int AccessFailedCount { get; set; }
public virtual ICollection<AspNetUserClaim> AspNetUserClaims { get; set; }
public virtual ICollection<AspNetUserLogin> AspNetUserLogins { get; set; }
public virtual ICollection<AspNetUserRole> AspNetUserRoles { get; set; }
public virtual ICollection<AspNetUserToken> AspNetUserTokens { get; set; }
}
public partial class AspNetUserConfigure : IEntityTypeConfiguration<AspNetUser>
{
public void Configure(EntityTypeBuilder<AspNetUser> builder)
{
builder.HasIndex(e => e.NormalizedEmail)
.HasName("EmailIndex");
builder.HasIndex(e => e.NormalizedUserName)
.HasName("UserNameIndex")
.IsUnique()
.HasFilter("([NormalizedUserName] IS NOT NULL)");
builder.Property(e => e.Email).HasMaxLength(256);
builder.Property(e => e.NormalizedEmail).HasMaxLength(256);
builder.Property(e => e.NormalizedUserName).HasMaxLength(256);
builder.Property(e => e.UserName).HasMaxLength(256);
}
}
}
和 MyDbContext
(在另一个 class 库中),在我的项目中,我使用反射和 IEntityTypeConfiguration
自动创建 DbSets 的接口:
public class ApplicationDbContext : IdentityDbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
var entitiesAssembly = typeof(IEntity).Assembly;
modelBuilder.RegisterAllEntities<IEntity>(entitiesAssembly);
modelBuilder.RegisterEntityTypeConfiguration(entitiesAssembly);
modelBuilder.AddRestrictDeleteBehaviorConvention();
modelBuilder.AddSequentialGuidForIdConvention();
modelBuilder.AddPluralizingTableNameConvention();
OnModelCreatingPartial(modelBuilder);
}
partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
}
但是
partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
方法,我得到一个错误:
A partial method must be declared within a partial class, partial struct, or partial interface
我不知道如何解决这个错误。有人可以帮我吗?
第二个问题:我的 DbContext
是否需要从 IdentityDbContext
class 继承?
既然你问的是你是否应该从 IdentityDbContext
继承你的 class,我的回答将是一个响亮的是的 。通过这样做,您将不必反编译库代码并自己支持它。 Microsoft 和社区为您维护它做得很好 - 节省您的时间。因此,这也有望解决您的第一个问题。
据我所知,您已经从库存标准库中复制了所有 DbSet
属性和大部分 AspNetUserConfigure
。对于这个答案,我假设您想覆盖某些行为并将 .HasFilter("([NormalizedUserName] IS NOT NULL)")
添加到您的 AspNetUser
.
public class aspnetpakshavadContext: IdentityDbContext {
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("your-connection-string"); // you will notice I removed .IsConfigured check - I believe this is redundant as OnConfiguring should always have it set to `false`
}
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(builder); // this is calling all relevant code from IdentityDbContext that you have previously copied. Yours will go afterwards to ensure your changes are applied last
modelBuilder.ApplyConfiguration(new MyAspNetUserConfiguration());// your extension point to modify particular entity model
}
public class MyAspNetUserConfiguration: IEntityTypeConfiguration<PortalUser>
{
public void Configure(EntityTypeBuilder<AspNetUser> builder)
{
builder.HasFilter("([NormalizedUserName] IS NOT NULL)"); // Builders are chained, so as long as you've called this after base method `OnModelCreating` above - this should add to existing model.
}
}
}
希望这就是您所追求的。
附带说明一下,我不确定您的部分实现来自哪里,因为 IdentityDbContext
的原始代码似乎没有任何...