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")));
问题原因
- EF实体实例化逻辑限制:EF Core生成的实体类(如Config)由DbContext负责实例化,不会通过DI容器创建,因此构造函数中注入的
IDbContextFactory<DataContext>永远不会被DI容器填充,_dataContext始终为null。 - 静态方法设计错误:静态方法属于类本身,无法访问实例成员
_dataContext,即便实例能拿到注入对象,静态方法也无法调用。
解决方案
方案1:将配置操作移到独立服务类(推荐)
把Config相关业务逻辑从实体类剥离,创建专门的配置服务由DI容器管理,正常注入依赖。
代码实现
- 定义服务接口与实现类:
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; } } }
- 在Program.cs注册服务:
builder.Services.AddScoped<IConfigService, ConfigService>();
- 在需要的地方注入服务使用:
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
相关产品推荐
相关产品推荐

