.net EF Core:一个数据库支持多个DbContext

noj0wjuj  于 2023-02-06  发布在  .NET
关注(0)|答案(1)|浏览(198)

我试图重新点燃这个主题。它曾经开始over 10 years ago,虽然有一些评论是几年前,现在已经关闭。然而,这仍然是一种不清楚我。
很多人对此发表了自己的观点,虽然有一些很好的理由和观点,但实际的方法和总体结论仍然不清楚,至少对我来说是这样。
我的情况:我正在尝试创建一种比必要的应用程序更复杂的方法来研究和测试东西。到目前为止,我一直只使用一个DbContext,现在我希望通过创建一个新的身份/安全性来将其分离(我知道IdentityDbContext存在,虽然这是一个更聪明的解决方案,但我想尝试一下)当我设法配置第二个DbContext并创建迁移时,迁移状态已重置为"初始",并创建了新表(而不是使用旧表)。
我的问题:以下哪一个是应用新DbContext的良好实用示例,以及如何将到目前为止的迁移快照复制到新DbContext(以便继续执行序列)。此外,将迁移快照的未来状态复制到原始DbContext等。
下面是我设法编写的一些代码示例:
这是DbContexts的基类扩展的一部分。

public class DbContextExtend : DbContext
    {
        protected readonly ICurrentUserService _userService;
        protected readonly IDateTime _dateTime;

        public DbContextExtend(DbContextOptions<ReservationDbContext> options) : base(options) { }

        public DbContextExtend(DbContextOptions<ReservationDbContext> options,
            IDateTime datetime,
            ICurrentUserService userService) : base(options)
        {
            _dateTime = datetime;
            _userService = userService;
        }

        public DbContextExtend(DbContextOptions<SecurityDbContext> options) : base(options) { }
        public DbContextExtend(DbContextOptions<SecurityDbContext> options,
            IDateTime datetime,
            ICurrentUserService userService) : base(options)
        {
            _dateTime = datetime;
            _userService = userService;
        }
        public DbSet<Audit> Audits { get; set; }
        public async override Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
        {
            //var auditEntries = await OnBeforeSaveChangesAsync();
            var result = await base.SaveChangesAsync(cancellationToken);
            //await OnAfterSaveChanges(auditEntries);

            return result;
        }
   }

一个新引入的DbContext-OnModelCreating、Ignore Reservations和它后面的所有内容,以便专注于3个重要的表(有没有更好的方法来做到这一点)。

public class SecurityDbContext : DbContextExtend, ISecurityDbContext
    {
        public SecurityDbContext(DbContextOptions<SecurityDbContext> options) : base(options) { }

        public SecurityDbContext(DbContextOptions<SecurityDbContext> options,
            IDateTime datetime,
            ICurrentUserService userService) : base(options, datetime, userService) { }
        public DbSet<User> Users { get; set; }
        public DbSet<LoginDetails> LoginDetails { get; set; }
        public DbSet<Role> Roles { get; set; }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);

            modelBuilder.ApplyConfiguration(new Configurations.SecurityConfiguration.RoleConfiguration());
            modelBuilder.ApplyConfiguration(new Configurations.SecurityConfiguration.UserConfiguration());
            modelBuilder.ApplyConfiguration(new Configurations.SecurityConfiguration.LoginDetailsConfiguration());
            modelBuilder.Ignore<Reservation>();
        }
    }

到目前为止一直在使用的DbContext。忽略应该不在其中的表LoginDetails。

public class ReservationDbContext : DbContextExtend, IReservationDbContext
    {
        public ReservationDbContext(DbContextOptions<ReservationDbContext> options) : base(options) { }

        public ReservationDbContext(DbContextOptions<ReservationDbContext> options,
            IDateTime datetime,
            ICurrentUserService userService) : base(options, datetime, userService) { }
        public DbSet<Role> Roles { get; set; }
        public DbSet<User> Users { get; set; }
        public DbSet<LoginDetails> LoginDetails { get; set; }
        public DbSet<EventType> EventTypes { get; set; }
        public DbSet<Event> Events { get; set; }
        public DbSet<Question> Questions { get; set; }
        public DbSet<EventQuestion> EventQuestions { get; set; }
        public DbSet<EventOccurrence> EventOccurrences { get; set; }
        public DbSet<Ticket> Tickets { get; set; }
        public DbSet<Reservation> Reservations { get; set; }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);

            modelBuilder.ApplyConfiguration(new EventTypeConfiguration());
            modelBuilder.ApplyConfiguration(new EventConfiguration());
            modelBuilder.ApplyConfiguration(new QuestionConfiguration());
            modelBuilder.ApplyConfiguration(new EventOccuranceConfiguration());
            modelBuilder.ApplyConfiguration(new ReservationConfiguration());
            modelBuilder.ApplyConfiguration(new TicketConfiguration());
            modelBuilder.ApplyConfiguration(new UserConfiguration());
            modelBuilder.ApplyConfiguration(new RoleConfiguration());
            modelBuilder.Ignore<LoginDetails>();
        }
    }

UserConfiguration-配置的一个示例,它是一个分隔两个上下文的表(但包含在两个上下文中)。

public class UserConfiguration : AuditableEntityConfiguration<User>
    {
        public override void ConfigureAuditableEntity(EntityTypeBuilder<User> builder)
        {
            builder.HasKey(u => u.Id);
            builder.Property(u => u.Email)
                .HasMaxLength(128)
                .IsRequired();
            builder.Property(u => u.Name)
                .IsRequired();
            builder.Property(u => u.PhoneNumber)
                .HasMaxLength(20)
                .IsRequired(false);;
            builder.Property(u => u.RoleId)
                .IsRequired();
            builder.HasOne(u => u.Role)
                .WithMany(r => r.Users)
                .HasForeignKey(u => u.RoleId);
            builder.HasOne(u => u.LoginDetails)
                .WithOne(ld => ld.User)
                .HasForeignKey<LoginDetails>(u => u.UserId)
                .IsRequired();
        }
    }

值得注意的是,我还决定将SecurityDbContext逻辑分离到不同的项目中。
请随时给我所有的建议和现实世界的经验,你可以。我会非常感谢!

k97glaaz

k97glaaz1#

您应该为每个DbContext生成不同的迁移。如果您希望在同一个数据库表中有不同的实体,请使用ToTable()方法在每个配置中显式地说明这一点。此外,它们的配置应该匹配。最后,您还应该显式地说明数据库名称,因此在每个OnModelCreating中,您应该在builder.HasDefaultScheme()中传递相同的值。
假设我有一个IdentityDbContext,它继承自IdentityDbContext〈〉,这是asp中的默认值,但是我有一个继承自IdentityUser的AppUser,所以我有一个配置,然后我会得到如下内容:

public class IdentityDbContext : IdentityDbContext<AppUser>
{
    //Other stuff

    protected override void OnModelCreating(ModelBuilder builder)
    {
        builder.HasDefaultSchema("TestDb");
        builder.ApplyConfiguration(new AppUserConfiguration())
        base.OnModelCreating(builder);
    }

}

然后,我有一个从DbContext继承的WriteDbContext,并且我有一个客户的配置:

public class WriteDbContext : DbContext
{
    public DbSet<Customer> Customers { get; set; }

    //Other stuff

    protected override void OnModelCreating(ModelBuilder builder)
    {
        builder.HasDefaultSchema("TestDb");
        builder.ApplyConfiguration(new CustomerConfiguration())
        base.OnModelCreating(builder);
     }
}

这时,我需要为每个DbContext生成一个迁移,然后应用它们,这样我就可以在同一个数据库中包含所有的身份信息和客户。
我还可以有一个CustomerReadModel,它只能用于读取,因此它没有任何逻辑、私有字段,并且可能具有到其他ReadModel的导航,只要它们都具有相同的配置,例如它们中的FirstName都配置为nvarchar(50),如果客户只有一个地址(作为实体),则CustomerReadModel也具有一个或其具有配置为地址的AddressReadModel等,在两种配置中,我都有**builder.ToTable(“Customers”)**它们都将指向同一个客户数据库表:

public class ReadDbContext: DbContext
{
    public DbSet<CustomerReadModel> Customers{ get; set; }

    //Other stuff

    protected override void OnModelCreating(ModelBuilder builder)
    {
        builder.HasDefaultSchema("TestDb");
        builder.ApplyConfiguration(new CustomerReadModelConfiguration())
        base.OnModelCreating(builder);
    }
}

现在我不应该为ReadDbContext添加迁移,因为数据库已经配置好了。
如果您愿意,也可以查看这些内容(免责声明:他们是我的):
https://www.youtube.com/watch?v=QkHfBNPvLms
https://www.youtube.com/watch?v=MNtXz4WvclQ
编辑:我做了一个演示前一段时间,有以上一些:https://github.com/spyroskatsios/MakeYourBusinessGreen

相关问题