You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将多组重复的DbSet批量插入代码重构为统一执行逻辑?

重构IdentityServer配置数据插入的重复逻辑

问题背景

当前代码中存在多组重复的if判断+foreach循环逻辑,用于将Config中的模型数据转换为实体后插入到configContext对应的DbSet中,每组逻辑仅针对的集合类型不同,需重构为统一执行逻辑以消除重复代码。

类型说明

configContext下的实体集合

  • configContext!.Clients:Duende.IdentityServer.EntityFramework.Entities.Client
  • configContext!.IdentityResources:Duende.IdentityServer.EntityFramework.Entities.IdentityResource
  • configContext!.ApiScopes:Duende.IdentityServer.EntityFramework.Entities.ApiScope
  • configContext!.ApiResources:Duende.IdentityServer.EntityFramework.Entities.ApiResource

Config下的模型集合

  • Config.Clients:Duende.IdentityServer.Models.Client
  • Config.IdentityResources:Duende.IdentityServer.Models.IdentityResource
  • Config.ApiScopes:Duende.IdentityServer.Models.ApiScope
  • Config.ApiResources:Duende.IdentityServer.Models.ApiResource

原重复代码

// 向数据库添加OAuth2和OpenID Connect客户端
if (configContext!.Clients.Any() == false)
{
    foreach (Client client in Config.Clients)
    {
        configContext.Clients.Add(client.ToEntity());
    }
    configContext.SaveChanges();
}

// 向数据库添加用户相关信息(如邮箱、用户ID等)
if (configContext.IdentityResources.Any() == false)
{
    foreach (IdentityResource resource in Config.IdentityResources)
    {
        configContext.IdentityResources.Add(resource.ToEntity());
    }
    configContext.SaveChanges();
}

// 向数据库添加API访问范围
if (configContext.ApiScopes.Any() == false)
{
    foreach (ApiScope apiAccess in Config.ApiScopes)
    {
        configContext.ApiScopes.Add(apiAccess.ToEntity());
    }
    configContext.SaveChanges();
}

// 向数据库添加需保护的API
if (configContext.ApiResources.Any() == false)
{
    foreach (ApiResource api in Config.ApiResources)
    {
        configContext.ApiResources.Add(api.ToEntity());
    }
    configContext.SaveChanges();
}

重构方案

方案1:封装泛型处理方法(推荐,类型安全)

通过泛型方法抽离所有重复逻辑,仅需传入目标DbSet、源模型集合以及模型转实体的委托即可:

/// <summary>
/// 批量插入配置数据到指定DbSet
/// </summary>
/// <typeparam name="TModel">配置模型类型</typeparam>
/// <typeparam name="TEntity">数据库实体类型</typeparam>
/// <param name="dbSet">目标DbSet</param>
/// <param name="models">源模型集合</param>
/// <param name="convertToEntity">模型转实体的转换方法</param>
private void SeedConfigData<TModel, TEntity>(DbSet<TEntity> dbSet, IEnumerable<TModel> models, Func<TModel, TEntity> convertToEntity)
    where TEntity : class
{
    if (!dbSet.Any())
    {
        foreach (var model in models)
        {
            dbSet.Add(convertToEntity(model));
        }
        configContext.SaveChanges();
    }
}

调用时只需传入对应参数:

SeedConfigData(configContext.Clients, Config.Clients, model => model.ToEntity());
SeedConfigData(configContext.IdentityResources, Config.IdentityResources, model => model.ToEntity());
SeedConfigData(configContext.ApiScopes, Config.ApiScopes, model => model.ToEntity());
SeedConfigData(configContext.ApiResources, Config.ApiResources, model => model.ToEntity());

方案2:统一遍历映射集合(适合批量扩展场景)

若后续可能新增更多配置类型,可将所有映射关系整理为集合后统一遍历处理:

// 定义所有配置项的映射关系
var seedMappings = new List<(DbSet<object> EntitySet, IEnumerable<object> Models, Func<object, object> Converter)>
{
    (configContext.Clients.Cast<object>(), Config.Clients.Cast<object>(), m => ((Duende.IdentityServer.Models.Client)m).ToEntity()),
    (configContext.IdentityResources.Cast<object>(), Config.IdentityResources.Cast<object>(), m => ((Duende.IdentityServer.Models.IdentityResource)m).ToEntity()),
    (configContext.ApiScopes.Cast<object>(), Config.ApiScopes.Cast<object>(), m => ((Duende.IdentityServer.Models.ApiScope)m).ToEntity()),
    (configContext.ApiResources.Cast<object>(), Config.ApiResources.Cast<object>(), m => ((Duende.IdentityServer.Models.ApiResource)m).ToEntity())
};

// 统一执行插入逻辑
foreach (var mapping in seedMappings)
{
    if (!mapping.EntitySet.Any())
    {
        foreach (var model in mapping.Models)
        {
            mapping.EntitySet.Add(mapping.Converter(model));
        }
        configContext.SaveChanges();
    }
}

方案说明

  • 方案1利用泛型的类型约束保证类型安全,代码可读性高,维护成本低,适合当前场景。
  • 方案2通过统一管理映射关系,后续新增配置类型时仅需添加映射项即可,扩展性更强,但牺牲了部分类型安全性。

内容的提问来源于stack exchange,提问作者user20291437

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 07:50:31