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

EF Core实体部分类中DI访问DbContext失效的解决办法

问题描述

我正在构建Hangfire应用,已通过EF Core反向生成数据库模型。创建了Config实体的部分类,希望在其中访问DbContext进行配置相关操作,但依赖注入(DI)在该部分类中无法生效,其他场景DI功能正常。相关代码如下:

文件1:自动生成的Config实体类

public partial class Config
{
    public string Name { get; set; }
    public string Value { get; set; }
    public string Description { get; set; }

    public bool IsUserManaged { get; set; }

    public string ConfigurationGroup { get; set; }

    public int CreatedBy { get; set; }
    public DateTime CreationTime { get; set; }
    public DateTime? LastModificationTime { get; set; }

    public int? LastModifiedBy { get; set; }
}

文件2:Config实体的部分扩展类

public partial class Config
{
    private IDbContextFactory<DataContext> _dataContext;
 
    public Config(IDbContextFactory<DataContext> dataContext)
    {
        _dataContext = dataContext
    }

    public static T GetConfigValue<T>(string key, T defaultValue, DataContext existingContext = null)
    {
        if (existingContext != null)
        {
            return GetConfigValue(existingContext, key, defaultValue);
        }
 
        return GetConfigValue(_dataContext, key, defaultValue);
    }

    public static T GetConfigValue<T>(DataContext ctx, string key)
    {
        return GetConfigValue(ctx, key, default(T));
    }

    public static T GetConfigValue<T>(DataContext ctx, string key, T defaultValue)
    {
        var value = GetRawConfigValue(ctx, key);
 
        if (String.IsNullOrEmpty(value)) 
            return defaultValue;

        try
        {
            var conv = TypeDescriptor.GetConverter(typeof(T));
            var item = (T)conv.ConvertFrom(null, CultureInfo.InvariantCulture, value);

            return item;
        }
        catch
        {
            return defaultValue;
        }
    }

    private static readonly Func<DataContext, string, string> GetRawConfigValue =
        (context, key) => (from c in context.Configs
                           where c.Name == key.ToString()
                           select c.Value).FirstOrDefault();
}

Program.cs中的DbContext初始化

builder.Services.AddDbContextFactory<DataContext>(options => options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));

问题原因
  1. EF实体实例化逻辑限制:EF Core生成的实体类(如Config)由DbContext负责实例化,不会通过DI容器创建,因此构造函数中注入的IDbContextFactory<DataContext>永远不会被DI容器填充,_dataContext始终为null。
  2. 静态方法设计错误:静态方法属于类本身,无法访问实例成员_dataContext,即便实例能拿到注入对象,静态方法也无法调用。

解决方案

方案1:将配置操作移到独立服务类(推荐)

把Config相关业务逻辑从实体类剥离,创建专门的配置服务由DI容器管理,正常注入依赖。

代码实现

  1. 定义服务接口与实现类:
public interface IConfigService
{
    T GetConfigValue<T>(string key, T defaultValue, DataContext existingContext = null);
    T GetConfigValue<T>(string key);
}

public class ConfigService : IConfigService
{
    private readonly IDbContextFactory<DataContext> _dbContextFactory;

    public ConfigService(IDbContextFactory<DataContext> dbContextFactory)
    {
        _dbContextFactory = dbContextFactory;
    }

    public T GetConfigValue<T>(string key, T defaultValue, DataContext existingContext = null)
    {
        if (existingContext != null)
        {
            return GetConfigValue(existingContext, key, defaultValue);
        }

        using var ctx = _dbContextFactory.CreateDbContext();
        return GetConfigValue(ctx, key, defaultValue);
    }

    public T GetConfigValue<T>(string key)
    {
        return GetConfigValue(key, default(T));
    }

    private static T GetConfigValue<T>(DataContext ctx, string key, T defaultValue)
    {
        var value = ctx.Configs.FirstOrDefault(c => c.Name == key)?.Value;

        if (string.IsNullOrEmpty(value))
            return defaultValue;

        try
        {
            var conv = TypeDescriptor.GetConverter(typeof(T));
            var item = (T)conv.ConvertFrom(null, CultureInfo.InvariantCulture, value);
            return item;
        }
        catch
        {
            return defaultValue;
        }
    }
}
  1. 在Program.cs注册服务:
builder.Services.AddScoped<IConfigService, ConfigService>();
  1. 在需要的地方注入服务使用:
public class SampleHangfireJob
{
    private readonly IConfigService _configService;

    public SampleHangfireJob(IConfigService configService)
    {
        _configService = configService;
    }

    public void Run()
    {
        var maxRetry = _configService.GetConfigValue<int>("MaxRetryCount", 3);
        // 执行业务逻辑
    }
}

方案2:修改现有实体类代码(不推荐)

如果必须保留实体类中的方法,需调整静态方法参数,手动传入DbContextFactory,同时移除无效的构造注入:

修改后的文件2代码

public partial class Config
{
    // 移除无效的构造注入
    // private IDbContextFactory<DataContext> _dataContext;
    // public Config(IDbContextFactory<DataContext> dataContext) => _dataContext = dataContext;

    public static T GetConfigValue<T>(IDbContextFactory<DataContext> dbContextFactory, string key, T defaultValue)
    {
        using var ctx = dbContextFactory.CreateDbContext();
        return GetConfigValue(ctx, key, defaultValue);
    }

    public static T GetConfigValue<T>(DataContext ctx, string key)
    {
        return GetConfigValue(ctx, key, default(T));
    }

    public static T GetConfigValue<T>(DataContext ctx, string key, T defaultValue)
    {
        var value = ctx.Configs.FirstOrDefault(c => c.Name == key)?.Value;
 
        if (string.IsNullOrEmpty(value)) 
            return defaultValue;

        try
        {
            var conv = TypeDescriptor.GetConverter(typeof(T));
            var item = (T)conv.ConvertFrom(null, CultureInfo.InvariantCulture, value);
            return item;
        }
        catch
        {
            return defaultValue;
        }
    }
}

调用方式

在需要的地方从DI容器获取DbContextFactory传入:

public class SampleHangfireJob
{
    private readonly IDbContextFactory<DataContext> _dbContextFactory;

    public SampleHangfireJob(IDbContextFactory<DataContext> dbContextFactory)
    {
        _dbContextFactory = dbContextFactory;
    }

    public void Run()
    {
        var maxRetry = Config.GetConfigValue(_dbContextFactory, "MaxRetryCount", 3);
        // 执行业务逻辑
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 10:53:12