【译】在 ABP 框架项目中配置多个数据库上下文

介绍

随着组织的发展和变得更加复杂,您可能会发现自己有多个数据库平台来满足不同的需求。例如,您可能希望在报表实体上利用 NoSQL 方法来利用该平台的速度和动态对象灵活性,同时在传统的 SQL 解决方案中维护更结构化的数据元素。本文旨在引导您完成扩展 ABP 框架解决方案和利用多数据库体系结构的基本步骤。

源码

此应用程序的源代码可以在 GitHub 上找到。

要求

运行解决方案需要以下工具:
• .NET 6.0 SDK
• MongoDb服务器
• SQL Server

发展

创建项目

首先,我们将通过命令行创建一个新的 ABP 框架项目。由于我们将使用 SQL 实例作为默认数据库,因此我们将在命令行中指定:
abp new MultipleDbContextDemo -t app -u mvc --mobile none --database-provider ef -csf
更新连接字符串
在主 Web 项目中,打开文件并使用相应的连接字符串添加更新对象:appsettings.jsonConnectionStrings

"ConnectionStrings": {
    "Default": "Server=localhost;Database=MultipleDbContextDemo;Trusted_Connection=True",
    "Mongo": "mongodb://localhost:27017/MultipleDbContextDemo"
  },

对解决方案的 Db 移动器项目中的文件重复此过程。appsettings.json
添加要由 MongoDb 处理的实体类型
好吧,所以我们拆分 DbContext 是有原因的。为了模拟这个过程,我们将创建一个由MongoDb显式处理的实体,以便我们可以在DbContext中定义它。首先在项目下添加一个目录,并在另一个下添加一个目录。在这里,我们将放置构成数据元素的类文件,这些文件进入 MongoDb。MultipleDbContext.DomainDataElementSubDataElement

创建类SubDataElements

在目录中,创建一个名为 的新类,并使用以下内容填充它:SubDataElementsSubDataElement.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MultipleDbContextDemo.SubDataElements
{
    public class SubDataElement 
    {
        public SubDataElement()
        {
        }

        public SubDataElement(string name, string value)
        {
            Name = name;
            Value = value;
        }

        public string Name { get; set; }
        public string Value { get; set; }

        public override bool Equals(object obj)
        {
            SubDataElement subDataElement = obj as SubDataElement;
            
            if(subDataElement == null) return false;
            if (!string.Equals(subDataElement.Name, this.Name, StringComparison.InvariantCultureIgnoreCase)) return false;
            if (!string.Equals(subDataElement.Value, this.Value, StringComparison.InvariantCultureIgnoreCase)) return false;

            return true;
        }
    }
}

注意:此类将嵌套在类中,因此我们不需要定义 ABP 实体声明。DataElement

创建实体DataElements

在目录中,创建一个新类,并使用以下内容进行填充:DataElementsDataElement.cs

using MultipleDbContextDemo.SubDataElements;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Domain.Entities.Auditing;

namespace MultipleDbContextDemo.DataElements
{
    public class DataElement : FullAuditedAggregateRoot<Guid>
    {
        public DataElement()
        {
        }

        public DataElement(string name, string description)
        {
            Name = name;
            Description = description;
        }

        [NotNull]
        public string Name { get; set; }

        [NotNull]
        public string Description { get; set; }

        public ICollection<SubDataElement> SubDataElements { get; private set; } = new Collection<SubDataElement>();


        /* helper methods for handling the SubDataElements collection */
        private bool IsInSubDataElements(SubDataElement subDataElement)
        {
            return SubDataElements.Any(x=>x.Equals(subDataElement));
        }

        public void AddSubDataElement(SubDataElement subDataElement)
        {
            Check.NotNull(subDataElement, nameof(subDataElement));

            if(IsInSubDataElements(subDataElement))
            {
                return;
            }

            SubDataElements.Add(subDataElement);
        }

        public void RemoveSubDataElement(SubDataElement subDataElement)
        {
            Check.NotNull(subDataElement, nameof(subDataElement));

            if (!IsInSubDataElements(subDataElement))
            {
                return;
            }

            SubDataElements.RemoveAll(x => x.Equals(subDataElement));
        }

        public void RemoveAllSubDataElements()
        {
            SubDataElements.Clear();
        }

    }
}

注意:这是我们的根实体,它包含未定义为实体的对象集合,因此与MongoDb等无模式数据库解决方案比MSSQL等基于模式的解决方案更兼容。

创建文件IDataElementRepository.cs

在目录中,创建一个新类并添加以下内容:DataElementsIDataElementRepository.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.Domain.Repositories;

namespace MultipleDbContextDemo.DataElements
{
    public interface IDataElementRepository : IRepository<DataElement, Guid>
    {
    }
}

创建文件DataElementManager.cs

在目录中,创建一个新类文件,并添加以下内容:DataElementsDataElementManager

using MultipleDbContextDemo.SubDataElements;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Domain.Services;

namespace MultipleDbContextDemo.DataElements
{
    public class DataElementManager : DomainService
    {
        private readonly IDataElementRepository _dataElementRepository;

        public DataElementManager(IDataElementRepository dataElementRepository)
        {
            _dataElementRepository = dataElementRepository;
        }

        public async Task<DataElement> CreateAsync(string name, string description, ICollection<SubDataElement> subDataElements = null)
        {
            Check.NotNull(name, nameof(name));
            Check.NotNull(description, nameof(description));

            var dataElement = new DataElement(GuidGenerator.Create(), name, description);

            if(subDataElements != null)
            {
                foreach(var subDataElement in subDataElements)
                {
                    dataElement.AddSubDataElement(subDataElement);
                }    
            }

            return await _dataElementRepository.InsertAsync(dataElement);
        }

        public async Task<DataElement> UpdateAsync(Guid id, string name, string description, ICollection<SubDataElement> subDataElements = null)
        {
            Check.NotNull(name, nameof(name));
            Check.NotNull(description, nameof(description));

            var dataElement = (await _dataElementRepository.WithDetailsAsync()).Where(x => x.Id == id).FirstOrDefault();

            if (dataElement == null || dataElement == default)
                throw new UserFriendlyException($"Data Element not found with Id: {id}");

            dataElement.Name = name;
            dataElement.Description = description;

            if (subDataElements != null)
            {
                subDataElements = new Collection<SubDataElement>();
                foreach (var subDataElement in subDataElements)
                {
                    dataElement.AddSubDataElement(subDataElement);
                }
            }

            return await _dataElementRepository.UpdateAsync(dataElement);
        }
    }
}

创建文件DataElementDataSeedContributor.cs

我们希望看到运行中的数据,因此请创建一个数据种子参与者,以将一些初始数据添加到存储库中。在目录中,创建一个调用以下内容的新文件:DataElementsDataElementDataSeedContributor.cs

using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Guids;

namespace MultipleDbContextDemo.DataElements
{
    public class DataElementDataSeedContributor : IDataSeedContributor, ITransientDependency
    {
        private readonly IDataElementRepository _dataElementRepository;
        private readonly IGuidGenerator _guidGenerator;

        public DataElementDataSeedContributor(IDataElementRepository dataElementRepository, IGuidGenerator guidGenerator)
        {
            _dataElementRepository = dataElementRepository;
            _guidGenerator = guidGenerator;
        }

        public async Task SeedAsync(DataSeedContext context)
        {
            if(await _dataElementRepository.GetCountAsync() == 0)
            {
                var dataElements = new List<DataElement>();

                var de1 = new DataElement(_guidGenerator.Create(), "DataElement1", "The first Data Element");
                de1.AddSubDataElement(new SubDataElements.SubDataElement("DE1SE1", "Test Data 1"));
                de1.AddSubDataElement(new SubDataElements.SubDataElement("DE1SE2", "Test Data 2"));
                dataElements.Add(de1);

                var de2 = new DataElement(_guidGenerator.Create(), "DataElement2", "The second Data Element");
                de2.AddSubDataElement(new SubDataElements.SubDataElement("DE2SE1", "Test Data 1"));
                dataElements.Add(de2);

                var de3 = new DataElement(_guidGenerator.Create(), "DataElement3", "The third Data Element");
                de3.AddSubDataElement(new SubDataElements.SubDataElement("DE3SE1", "Test Data 1"));
                de3.AddSubDataElement(new SubDataElements.SubDataElement("DE3SE2", "Test Data 2"));
                de3.AddSubDataElement(new SubDataElements.SubDataElement("DE3SE3", "Test Data 3"));
                de3.AddSubDataElement(new SubDataElements.SubDataElement("DE3SE4", "Test Data 4"));
                dataElements.Add(de3);

                var de4 = new DataElement(_guidGenerator.Create(), "DataElement4", "The fourth Data Element");
                dataElements.Add(de4);

                await _dataElementRepository.InsertManyAsync(dataElements);
            }         
        }
    }
}

添加MongoDb项目

我不认为为MongoDb架构创建一个新项目是绝对必要的,但是为了保持代码结构整齐,我们将这样做。
专业提示:您可以使用以下命令在不同的文件夹中创建具有相同名称的新项目,并从那里复制MongoDb项目:。为了我们的目的,我们将明确地通过它abp new MultipleDbContextDemo -t app -u mvc --mobile none --database-provider mongodb -csf

添加项目

在主解决方案中,右键单击该文件夹并添加新项目。选择“类库”项目类型,并针对 .NET 6.0(长期支持)框架(或阅读本文时最新的任何框架)调用它。src MultipleDbContextDemo.MongoDb

创建项目时。删除默认文件并转到下一步。Class1.cs

使用必要的引用更新MultipleDbContextDemo.MongoDb.csproj

将以下行添加到 标记内的 csproj 文件中:<Project>

using MongoDB.Driver;
using MultipleDbContextDemo.DataElements;
using Volo.Abp;
using Volo.Abp.Data;
using Volo.Abp.MongoDB;

namespace MultipleDbContextDemo.MongoDb;

[ConnectionStringName("Mongo")]
public class MultipleDbContextDemoMongoDbContext : AbpMongoDbContext
{
    public IMongoCollection<DataElement> DataElements => Collection<DataElement>();

    protected override void CreateModel(IMongoModelBuilder modelBuilder)
    {
        Check.NotNull(modelBuilder, nameof(modelBuilder));

        base.CreateModel(modelBuilder);

        modelBuilder.Entity<DataElement>(b => { b.CollectionName = $"{MultipleDbContextDemoConsts.DbTablePrefix}DataElements"; });
    }
}

创建文件MultipleDbContextDemoMongoDbModule.cs
在目录中,创建一个新类,并放入以下内容:MongoDbMultipleDbContextDemoMongoDbModule.cs

using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Data;
using Volo.Abp.Modularity;
using Volo.Abp.MongoDB;
using Volo.Abp.Uow;

namespace MultipleDbContextDemo.MongoDb;

[DependsOn(
    typeof(MultipleDbContextDemoDomainModule)
    )]
[DependsOn(typeof(AbpMongoDbModule))]
public class MultipleDbContextDemoMongoDbModule : AbpModule
{
    public override void ConfigureServices(ServiceConfigurationContext context)
    {
        context.Services.AddMongoDbContext<MultipleDbContextDemoMongoDbContext>(options =>
        {
            options.AddDefaultRepositories();
        });

        Configure<AbpUnitOfWorkDefaultOptions>(options =>
        {
            options.TransactionBehavior = UnitOfWorkTransactionBehavior.Disabled;
        });
    }
}

创建文件MongoDataElementRepository.cs

这将实现接口并使用依赖关系注入进行注册。在项目中,创建一个目录,然后在该文件夹中创建一个类,该文件夹调用以下内容:IDataEntryRepositoryMultipleDbContextDemo.MongoDbDataElementsMongoDataElementRepository.cs

using MultipleDbContextDemo.DataElements;
using Volo.Abp.Domain.Repositories.MongoDB;
using Volo.Abp.MongoDB;

namespace MultipleDbContextDemo.MongoDb.DataElements
{
    public class MongoDataElementRepository : MongoDbRepository<MultipleDbContextDemoMongoDbContext, DataElement, Guid>, IDataElementRepository
    {
        public MongoDataElementRepository(IMongoDbContextProvider<MultipleDbContextDemoMongoDbContext> dbContextProvider) : base(dbContextProvider)
        {
        }
    }
}

这就是我们现在需要添加到MongoDb项目的全部内容。下一步是确保 Web 项目了解新的数据库上下文。

使用对新 MongoDb 项目的引用更新 Web 项目模块。

为了使服务在以后需要时可用,我们需要使主项目模块知道新的MongoDb项目。

编辑 以包MongoDb 项目参考MultipleDbContextDemo.Web.csproj

在编辑器中,打开文件并在标记底部添加以下行:MultipleDbContextDemo.Web.csproj

<ItemGroup>
    <ProjectReference Include="..\MultipleDbContextDemo.MongoDb\MultipleDbContextDemo.MongoDB.csproj" />
</ItemGroup>

添加对文件的引用MultipleDbContextDemoWebModule.cs

在编辑器中,打开文件并添加以下行:MultipleDbContextDemoWebModule.cs
• 在顶部的 using 子句中,添加:using MultipleDbContextDemo.MongoDb;
• 直接在类声明的上方,在现有的 DependsOn 语句上方(如果您愿意,也可以将其添加到现有语句中),添加:[DependsOn(typeof(MultipleDbContextDemoMongoDbModule))]
重要说明:您计划用于“默认”连接字符串的任何 DBMS 都必须在 DependsOn 语句中排在最后
添加这些内容后,您的项目现在应该知道新的 DbContext,并且它应该已准备好在代码中使用。接下来,我们需要更新数据库迁移器项目,以便它也知道新的 DbContext。

使用对新 MongoDb 项目的引用更新数据库迁移器项目模块。

这些步骤应该与我们刚刚在Web项目中执行的操作相同,我们只需要使Db移动器项目知道新的MongoDb项目。
编辑文件以包含MongoDb项目引用MultipleDbContextDemo.DbMigrator.csproj
在编辑器中,打开文件并在标记底部添加以下行:MultipleDbContextDemo.DbMigrator.csproj

<ItemGroup>
    <ProjectReference Include="..\MultipleDbContextDemo.MongoDb\MultipleDbContextDemo.MongoDB.csproj" />
</ItemGroup>

添加对文件的引用MultipleDbContextDemoDbMigratorModule.cs
在编辑器中,打开项目内的文件并添加以下行:MultipleDbContextDemoDbMigratorModule.csMultipleDbContextDemo.DbMigrator
• 在顶部的 using 子句中,添加:using MultipleDbContextDemo.MongoDb;
• 直接在类声明的上方,在现有的 DependsOn 语句上方(如果您愿意,也可以将其添加到现有语句中),添加:[DependsOn(typeof(MultipleDbContextDemoMongoDbModule))]
重要说明:您计划用于“默认”连接字符串的任何 DBMS 都必须在 DependsOn 语句中排在最后
生成解决方案并运行 Db 迁移器来设定数据库的种子。
生成解决方案以确保不会收到任何错误,然后右键单击该项目并选择“调试 ->启动新实例”。这将运行调试程序并为数据库设定种子。MultipleDbContextDemo.DbMigrator

如果查看数据库,您将看到所有 AbpModule 的标准数据元素都在 SQL 数据库中:

该表仅存在于 MongoDb 实例中:DataElement

您还会注意到 MongoDb 中的数据元素具有嵌套对象,这与我们在数据种子类中概述的完全一样:

此时,您应该能够在 App 服务中引入或通过依赖关系注入,并从 mongodb 进行读/写。IDataElementRepositoryDataElementManager

跳转原文地址

posted @ 2022-09-15 09:44  HUGO.CM  阅读(1280)  评论(0编辑  收藏  举报