EFCore 分表

pojianbing發表於2024-10-07

Program

internal class Program
{
    static async Task Main(string[] args)
    {
        DbContextOptionsBuilder<BloggingContext> optionsBuilder = new DbContextOptionsBuilder<BloggingContext>();
        optionsBuilder.UseSqlServer("Data Source=localhost;Initial Catalog=DemoA;Integrated Security=True;Encrypt=True;TrustServerCertificate=True;");
        var options = optionsBuilder.Options;

        using (var dbContext1 = new BloggingContext("202209", options))
        {
            var blog = dbContext1.Blogs.FirstOrDefault();
            Console.WriteLine("查詢成功: dbContext1");
        }

        using (var dbContext2 = new BloggingContext("202210", options))
        {
            var blog = dbContext2.Blogs.FirstOrDefault();
            Console.WriteLine("查詢成功: dbContext2");
        }

        Console.ReadKey();
    }
}

BloggingContext

public class BloggingContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }

    public string ShardingRule { get; }

    public BloggingContext(string shardingRule, DbContextOptions options) : base(options)
    {
        this.ShardingRule = shardingRule;
    }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        base.OnConfiguring(optionsBuilder);

        if (!string.IsNullOrWhiteSpace(this.ShardingRule))
        {
            optionsBuilder.ReplaceService<IModelCacheKeyFactory, DynamicModelCacheKeyFactoryDesignTimeSupport>()
                          .ReplaceService<IModelCustomizer, ShardingModelCustomizer>();
        }
    }

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

public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }
}

DynamicModelCacheKeyFactoryDesignTimeSupport

/// <summary>
/// 同一DBContext僅能執行OnModelCreating一次,自定義 IModelCacheKeyFactory,實現多次觸發
/// </summary>
public class DynamicModelCacheKeyFactoryDesignTimeSupport : IModelCacheKeyFactory
{
    public object Create(DbContext context, bool designTime)
    {
        return context is BloggingContext bloggingContext 
            ? (context.GetType(), bloggingContext.ShardingRule, designTime)
            : context.GetType();
    }

    public object Create(DbContext context)
       => Create(context, false);
}

ShardingModelCustomizer

/// <summary>
/// 修改模型定義
/// </summary>
public class ShardingModelCustomizer : ModelCustomizer
{
    public ShardingModelCustomizer(ModelCustomizerDependencies dependencies) : base(dependencies)
    {
    }

    public override void Customize(ModelBuilder modelBuilder, DbContext context)
    {
        base.Customize(modelBuilder, context);

        var bloggingContext = context as BloggingContext;
        if (bloggingContext == null) return;

        // 這裡為了演示,僅以Blog實體做演示。
        var type = typeof(Blog);

        // 對映到自定表
        modelBuilder.Entity(type).ToTable($"{type.Name}_{bloggingContext.ShardingRule}");
    }
}

相關文章