9.11、多上下文、读写分离
一个复杂的系统通常不止一个数据库,这是需要我们能够灵活的切换数据库操作上下文。
多上下文
默认情况下,Hoa Framework 只有一个默认的数据库上下文:Hoa.EntityFramewok.Core.HoaDbContext
,也就是默认只能操作一个数据库。
在 Hoa Framework 1.2.0 版本中,新增了多数据库上下文的支持。通过配置数据库多上下文可以同时操作多个数据库、并将数据库包裹在同一个事务中。
多上下文配置使用
第一步
在 appsetting.json
中新增新的数据库连接字符串。
{
"ConnectionStrings": {
"HoaDatabase": "Server=localhost;Database=Hoa;User=sa;Password=000000;",
"OtherDatabase": "Server=localhost;Database=Hoa;User=sa;Password=000000;"
}
}
第二步
在 Hoa.EntityFramework.Core
层创建新的 DbContext
,如 OtherDbContext
:
using Microsoft.EntityFrameworkCore;
namespace Hoa.EntityFrameworkCore
{
public partial class OtherDbContext : DbContext
{
public OtherDbContext(DbContextOptions<OtherDbContext> options)
: base(options)
{
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseSqlServer("Name=OtherDatabase");
}
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
OnModelCreatingPartial(modelBuilder);
}
partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
}
}
第三步
在 Hoa.Web.Core.ServiceExtensions.HoaDbContextConfigureExtension
中配置新的 DbContext
信息:
using Hoa.EntityFrameworkCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace Hoa.Web.Core.ServiceExtensions
{
public static class HoaDbContextConfigureExtension
{
public static IServiceCollection AddHoaDbContext(this IServiceCollection services, IWebHostEnvironment env)
{
services.AddDbContextPool<HoaDbContext>(options =>
{
options.UseSqlServer(AppGlobal.Configuration.GetConnectionString("HoaDatabase"));
if (env.IsDevelopment())
{
options/*.UseLazyLoadingProxies()*/
.EnableDetailedErrors()
.ConfigureWarnings(c => c.Log((RelationalEventId.CommandExecuting, LogLevel.Debug)));
}
}
, poolSize: 128);
// 配置 OtherDbContext
services.AddDbContextPool<OtherDbContext>(options =>
{
options.UseSqlServer(AppGlobal.Configuration.GetConnectionString("OtherDatabase"));
if (env.IsDevelopment())
{
options/*.UseLazyLoadingProxies()*/
.EnableDetailedErrors()
.ConfigureWarnings(c => c.Log((RelationalEventId.CommandExecuting, LogLevel.Debug)));
}
}
, poolSize: 128);
return services;
}
}
}
第四步
在 Hoa.Core
层创建 OtherDbContextIdentifier
数据库上下文标识类,注意:必须以 Identifier
结尾!!!并继承 DbContextIdentifier
类。
using Hoa.DbManager.Identifiers;
namespace Hoa.Core
{
public class OtherDbContextIdentifier : DbContextIdentifier
{
public OtherDbContextIdentifier() : base(nameof(OtherDbContextIdentifier))
{
}
}
}
第五步
在 Hoa.EntityFrameworkCore.HoaEntityFrameworkCoreModule
中新增配置代码:
using Autofac;
using Hoa.DbManager.Identifiers;
using Microsoft.EntityFrameworkCore;
namespace Hoa.EntityFrameworkCore
{
public class HoaEntityFrameworkCoreModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<HoaDbContext>()
.As<DbContext>()
.InstancePerLifetimeScope();
builder.RegisterType<HoaDbContext>()
.Named<DbContext>(nameof(HoaDbContextIdentifier))
.InstancePerLifetimeScope();
// 配置 OtherDbContext
builder.RegisterType<OtherDbContext>()
.Named<DbContext>(nameof(OtherDbContextIdentifier))
.InstancePerLifetimeScope();
}
}
}
第六步
上述配置好后,可以通过 IDynamicRepository<TEntity,TDbContextIdentifier>
初始化了:
using Hoa.Core.Test.Entities;
using Hoa.Dependencies;
using Hoa.ServiceController.Attributes;
using Hoa.UnitOfWork.Repositories;
using System.ComponentModel.DataAnnotations;
namespace Hoa.Application.Test
{
[HoaServiceController]
public class TestAppService : ITestAppService, IAppServiceDependency
{
private readonly IRepository<TestEntity> _testRepository;
// 初始化 OtherDbContext
private readonly IDynamicRepository<TestEntity,OtherDbContextIdentifier> _testOtherRepository;
public TestAppService(
IRepository<TestEntity> testRepository
// 在构造函数中注入
, IDynamicRepository<TestEntity,OtherDbContextIdentifier> testOtherRepository;
)
{
_testRepository = testRepository;
// 使用
_testOtherRepository = testOtherRepository;
}
// ... Other Codes
}
}
关键代码
private readonly IDynamicRepository<TestEntity,OtherDbContextIdentifier> _testOtherRepository;
读写分离配置
文档整理中......
关于分布式事务
在多数据库操作上下文操作数据库中,默认开启了分布式事务(同一个服务器内的不同数据库),如果数据库操作上下文不在同一个服务器上将报错:
System.PlatformNotSupportedException: This platform does not support distributed transactions.
那是因为 .NET Core 3.x 还不支持跨平台的分布式事务,需要在 .NET 5.x 版本才支持。
目前提供的解决方案是:在方法上面关闭分布式事务即可。