【问题标题】:How to use Multiple source Database using EF如何使用 EF 使用多源数据库
【发布时间】:2022-01-04 20:35:35
【问题描述】:

我尝试使用 Multiple DbContext 将项目的每个域迁移到不同的数据库,如下所示:

public class AppDbContext: DbContext
.
.
public class UserAccessDbContext: DbContext
.
.
public class AdministrationDbContext: DbContext
.
.
Etc

但看起来我做错了什么,所以我得到了每个 DbContext 中的所有表,我没有任何链接域的 FK。

每个 DbContext 的连接字符串如下:

public static void AppDbContext(this IServiceCollection services, string connectionString) =>
   services.AddDbContext<AppDbContext>(options => options.UseMySql(connectionString, new MySqlServerVersion(new Version(8, 0, 27))));

  public static void UserAccessDbContext(this IServiceCollection services, string connectionString) =>
   services.AddDbContext<UserAccessDbContext>(options => options.UseMySql(connectionString, new MySqlServerVersion(new Version(8, 0, 27))));
  
  public static void AdministrationDbContext(this IServiceCollection services, string connectionString) =>
   services.AddDbContext<AdministrationDbContext>(options => options.UseMySql(connectionString, new MySqlServerVersion(new Version(8, 0, 27))));

我的存储库是这样的:

public class AppRepository<T> : RepositoryBase<T>, IReadRepository<T>, IRepository<T> where T : class, IAggregateRoot
{
  public AppRepository(AppDbContext appDbContext) : base(appDbContext)
  {
  }
}
.
.
.
public class AdministrationRepository<T> : RepositoryBase<T>, IReadRepository<T>, IRepository<T> where T : class, IAggregateRoot
{
    public AdministrationRepository(AdministrationDbContext administrationdbContext) : base(administrationdbContext)
    {
    }
}
.
.
.
public class UserAccessRepository<T> : RepositoryBase<T>, IReadRepository<T>, IRepository<T> where T : class, IAggregateRoot
{
    public UserAccessRepository(UserAccessDbContext userAccessdbContext) : base(userAccessdbContext)
    {

    }
}

我也像这样注册了 repo:

public class DefaultInfrastructureModule : Module
{
  private readonly bool _isDevelopment = false;
  private readonly List<Assembly> _assemblies = new List<Assembly>();

  public DefaultInfrastructureModule(bool isDevelopment, Assembly? callingAssembly = null)
  {
    _isDevelopment = isDevelopment;
    var coreAssembly = Assembly.GetAssembly(typeof(User)); // TODO: Replace "Project" with any type from your Core project
    var infrastructureAssembly = Assembly.GetAssembly(typeof(StartupSetup));
    if (coreAssembly != null)
    {
      _assemblies.Add(coreAssembly);
    }
    if (infrastructureAssembly != null)
    {
      _assemblies.Add(infrastructureAssembly);
    }
    if (callingAssembly != null)
    {
      _assemblies.Add(callingAssembly);
    }
  }

  protected override void Load(ContainerBuilder builder)
  {
    if (_isDevelopment)
    {
      RegisterDevelopmentOnlyDependencies(builder);
    }
    else
    {
      RegisterProductionOnlyDependencies(builder);
    }
    RegisterCommonDependencies(builder);
  }

  private void RegisterCommonDependencies(ContainerBuilder builder)
  {
    //Start Repository Reg
    builder.RegisterGeneric(typeof(AppRepository<>))
        .As(typeof(IRepository<>))
        .As(typeof(IReadRepository<>))
        .InstancePerLifetimeScope();

    builder.RegisterGeneric(typeof(AdministrationRepository<>))
        .As(typeof(IRepository<>))
        .As(typeof(IReadRepository<>))
        .InstancePerLifetimeScope();

    builder.RegisterGeneric(typeof(UserAccessRepository<>))
        .As(typeof(IRepository<>))
        .As(typeof(IReadRepository<>))
        .InstancePerLifetimeScope();
    //End Repository Reg

    builder
        .RegisterType<Mediator>()
        .As<IMediator>()
        .InstancePerLifetimeScope();

    builder.Register<ServiceFactory>(context =>
    {
      var c = context.Resolve<IComponentContext>();
      return t => c.Resolve(t);
    });

    var mediatrOpenTypes = new[]
    {
      typeof(IRequestHandler<,>),
      typeof(IRequestExceptionHandler<,,>),
      typeof(IRequestExceptionAction<,>),
      typeof(INotificationHandler<>),
    };

    foreach (var mediatrOpenType in mediatrOpenTypes)
    {
      builder
      .RegisterAssemblyTypes(_assemblies.ToArray())
      .AsClosedTypesOf(mediatrOpenType)
      .AsImplementedInterfaces();
    }

    builder.RegisterType<EmailSender>().As<IEmailSender>()
      .InstancePerLifetimeScope();
  }

  private void RegisterDevelopmentOnlyDependencies(ContainerBuilder builder)
  {
    // TODO: Add development only services
  }

  private void RegisterProductionOnlyDependencies(ContainerBuilder builder)
  {
    // TODO: Add production only services
  }

}

我在我的代码中错过了什么来修复它!

任何帮助我该怎么做。

【问题讨论】:

  • 考虑到你不能有同名表的上下文,因为它们之间会发生崩溃类,即使它们在不同的实体模型中。
  • "so I get all Tables in each DbContext"你能详细说明一下吗?
  • 亲爱的@LeandroBardelli 我用更多细节更新我的问题。
  • 亲爱的@GuruStron 你也可以检查我的更新。
  • 对不起@sumer5020 但我们不以这种方式工作,我们需要具体的问题或代码来帮助您。请阅读有关如何提问的教程和指南

标签: c# entity-framework asp.net-core domain-driven-design .net-6.0


【解决方案1】:

如果我的问题是对的,那么情况可能是您目前正在开发一个单体应用程序并尝试将事物分离出来以围绕每个业务上下文进一步分离它们,......可能就像微服务?

我不知道你为什么要这样做的具体原因,但如果理由不值得,我建议你避免这样做。

我假设您已阅读上述建议,如果确实需要这样做,请先了解这些内容:

每个 DbContext 都可以配置自己的实体

假设我们有 10 个实体代表 3 个DbContext,我们可以将它们分开为 ADbContext 的 2 个实体,BDbContext 的 5 个实体和 CDbContext 的 3 个实体。像 FK 一样明智地管理它们之间的配置,否则就会变得混乱。下面是如何做到这一点,使用流畅的 API

public class MyAppDbContext : DbContext
{
    public DbSet<OurEntity> OurEntity { get; set; }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        builder.Entity<OurEntity>(builder => 
       {
            // Our implementation goes here...
       });
    }
}

像这样,我们只配置和注册每个DbContext对应的实体。

我们需要将每个 DbContext 分别注册到任何类型的 DI

您在上面的问题中执行此操作,那么我将跳过这部分。

为每个 DbContext 组织迁移操作

我通常将它们组织在这样的文件夹中:

  • 数据/迁移/ContextA
  • 数据/迁移/上下文B
  • 数据/迁移/上下文C

每个上下文都有自己的迁移和快照。

在使用 EF 迁移工具时通过指定单独的 DbContext 来做到这一点

dotnet ef migrations add [MigrationName] --context [DbContextName] --output-dir [Path to desire place to store migration]

然后分别应用它们

dotnet ef database update [MigrationName] --context [DbContextName]

就是这样。我们当然可以,但我仍然建议如果没有具体原因,我们应该避免这种方法。

【讨论】:

  • 亲爱的@Gordon,我今天工作的原因是我的项目处理大数据,我需要创建一个地方来管理我的日常工作和其他需要数据库强大功能的功能,所以我认为如果我在每一方之间分别处理我的数据,我可以以完美的方式完成它?
  • 另一方面,我需要使用“在处理您之前处理您的数据”的主体。
  • 如果解决方案很大,我强烈建议将流程管道分成较小的项目。它们可以位于同一个文件夹中,以便于版本控制和部署。如果解决方案不像我们认为的“复杂”那么大,那么我认为我们应该没问题。提醒一下,如果我们从头开始构建解决方案,对我们来说会很容易(因为我们完全控制了领域和上下文),但对于新来的人来说可能就不那么容易了。
  • 亲爱的@Gordon 我想我在使用 IEntityTypeConfiguration 时错过了一些东西
  • 在遇到困难之后,我发现了 DbContext 的问题,起初我使用 modelBuilder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly()); 来配置我的实体,但我的程序集出于某种原因总是将所有配置用于上下文,我尝试使用 modelBuilder.ApplyConfiguration(new AccGeneralJournalConfiguration());每个 DbContext 中的 OnModelCreating 并且它工作成功,但这让我有点困惑。
猜你喜欢
  • 2022-01-03
  • 2011-05-02
  • 1970-01-01
  • 1970-01-01
  • 2021-12-19
  • 2014-07-24
  • 1970-01-01
  • 1970-01-01
  • 2017-07-07
相关资源
最近更新 更多