首页 > 解决方案 > DbContext 实例不随依赖注入而改变

问题描述

在我的应用程序中,我有一个 API 和一个 worker,它们都需要使用我的数据库。我有一个存储库层,这两个都可以访问。我在我的应用程序中使用 DI,并将我的 dbContext 注入到我的存储库中。

虽然我希望我的存储库对每个请求都使用新的 dbContext,但实例似乎总是相同的。

由于我有一个后台工作人员,它是一个单例,我无法使用我的 dbContext 的默认作用域生命周期。因此,我在我的工作人员和我的 API 中都将我的 dbContext 添加为瞬态。我已将 instanceId 添加到我的 dbContext 中,它是在我的构造函数中设置的。

dbcontext 的构造函数:

 public CatAPIDbContext()
    {
        InstanceId = Guid.NewGuid();
        Database.EnsureCreated();
    }

工人配置服务:

  public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureServices((hostContext, services) =>
        {
            services.AddDbContext<CatAPIDbContext>(ServiceLifetime.Transient);
            services.AddTransient(typeof(IFeedingProfileRepository), typeof(FeedingProfileRepository));
            services.AddTransient(typeof(IFeedingTimesRepository), typeof(FeedingTimesRepository));
            services.AddTransient(typeof(IFeedHistoryRepository), typeof(FeedHistoryRepository));
            services.AddTransient(typeof(IMotorController), typeof(MotorController));
            services.AddTransient(typeof(IFoodDispenser), typeof(FoodDispenser));
            services.AddTransient(typeof(IGenericRepository<>), typeof(GenericRepository<>));
            services.AddTransient(typeof(IFeedingTimeChecker), typeof(FeedingTimeChecker));
            services.AddHostedService<Worker>();
        });

API 配置服务:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvcCore().SetCompatibilityVersion(CompatibilityVersion.Version_3_0);
    services.AddDbContext<CatAPIDbContext>();
    services.AddTransient(typeof(IFeedingProfileRepository), typeof(FeedingProfileRepository));
    services.AddTransient(typeof(IFeedingTimesRepository), typeof(FeedingTimesRepository));
    services.AddTransient(typeof(IFeedHistoryRepository), typeof(FeedHistoryRepository));
    services.AddTransient(typeof(IMotorController), typeof(MotorController));
    services.AddTransient(typeof(IFoodDispenser), typeof(FoodDispenser));
    services.AddTransient(typeof(IGenericRepository<>), typeof(GenericRepository<>));
}

通用回购示例:

public class GenericRepository<T> : IGenericRepository<T> where T : class
{
public CatAPIDbContext _dbContext { get; set; }
public GenericRepository(CatAPIDbContext dbContext)
{
    _dbContext = dbContext;
}

public T GetById(object id)
{
    return _dbContext.Set<T>().Find(id);
}
}

我使用但没有获得最新状态示例的回购:

 public class FeedingProfileRepository : 
GenericRepository<FeedingProfile>, IFeedingProfileRepository
{
    public FeedingProfileRepository(CatAPIDbContext dbContext) : 
base(dbContext)
    {
    }

    public FeedingProfile GetCurrentFeedingProfile()
    {
        var profile = _dbContext.FeedingProfiles
            .Include(x => x.TimesToFeedOn)
            .Where(x => x.CurrentlyActive == true).FirstOrDefault();


        if (profile == null)
        {
            return null;
        }
        if (profile.TimesToFeedOn != null)
        {
            profile.TimesToFeedOn = profile.TimesToFeedOn.OrderByDescending(x => x.Time).ToList();
        }
        return profile;

    }
}

当 thw orker 调用 FeedingProfileRepository.GetCurrentFeedingProfile() 时,我会检查 dbContext 的 instanceId,它在我的应用程序的整个生命周期中始终相同。结果,我从 dbContext 检索到的数据已经过时,并且与数据库的当前状态不匹配,因为 dbContext 永远不会被释放。难道我做错了什么?

标签: dependency-injectionentity-framework-corebackgroundworkerdbcontext

解决方案


正如我在您的代码中看到的那样,您已经制作了 dbContext Transient ,这意味着每次注入或请求它们时都会创建一个新实例:

 services.AddDbContext<CatAPIDbContext>(ServiceLifetime.Transient);

如果您想为所有请求提供一个实例,请将其设为单例尝试更改您的代码,如下所示:

services.AddDbContext<CatAPIDbContext>(ServiceLifetime.Singleton);

但是,如果您希望对应用程序的每个请求都有一个实例,请尝试使用作用域生命周期:

 services.AddDbContext<CatAPIDbContext>(ServiceLifetime.Scoped);

推荐阅读