我的实体框架项目无法从数据库获取当前信息

问题描述 投票:0回答:1

我在我的项目中使用实体框架,并且在流程项目中的某个点,它调用第二个系统来处理和更新数据库中的一些信息。

但是当第二个系统完成时,我的项目尝试再次从数据库获取此信息,但它返回旧信息。

我将 .NET 7.0 与 Entity Framework 6 和 SqLite 3.0 结合使用。

这是我的代码的一部分:

var assembly = Assembly.GetExecutingAssembly();
using var stream = assembly.GetManifestResourceStream("Totem.App.appsettings.json");

var config = new ConfigurationBuilder()
                    .AddJsonStream(stream)
                    .Build();
builder.Configuration.AddConfiguration(config);

var options = new DbContextOptionsBuilder<AppDbContext>()
                        .UseSqlite(DesignTimeDbContextFactory.GetConnectionString(config))
                        .Options;

var factory = new PooledDbContextFactory<AppDbContext>(options);
var context = factory.CreateDbContext();

builder.Services.AddDbContext<AppDbContext>(options => options.UseSqlite(DesignTimeDbContextFactory.GetConnectionString(config)));

builder.Services.AddScoped(typeof(IBaseRepository<>), typeof(BaseRepository<>));
builder.Services.AddScoped<IUserService, UserService>();
builder.Services.AddScoped<ICategoryService, CategoryService>();
builder.Services.AddScoped<IProductService, ProductService>();
builder.Services.AddScoped<IBannerService, BannerService>();
builder.Services.AddScoped<IAuthorService, AuthorService>();
builder.Services.AddScoped<IConfigService, ConfigService>();
builder.Services.AddScoped<IMeasureService, MeasureService>();
builder.Services.AddScoped<ICartService, CartService>();
builder.Services.AddScoped<IItemCartService, ItemCartService>();
builder.Services.AddScoped<IBranchService, BranchService>();

这是我的

BaseRepository

public class BaseRepository<TEntity> : IDisposable, IBaseRepository<TEntity> where TEntity :  class
{
        protected readonly AppDbContext _context;

        #region constructors
        public BaseRepository(AppDbContext context)
        {
            _context = context;
        }
        #endregion

        public void Dispose()
        {
            _context.Dispose();
            GC.SuppressFinalize(true);
        }

        public virtual void Insert(TEntity obj)
        {
            _context.Set<TEntity>().Add(obj);
        }

        public virtual void Update(TEntity obj)
        {
            _context.Entry(obj).State = Microsoft.EntityFrameworkCore.EntityState.Modified;
        }

        public virtual void Delete(int id)
        {
            _context.Set<TEntity>().Remove(GetById(id));
        }

        public virtual IQueryable<TEntity> GetAll()
        {
            return _context.Set<TEntity>();
        }

        public virtual TEntity GetById(int id)
        {
            return _context.Set<TEntity>().Find(id);
        }

        public virtual void SaveChanges()
        {
            _context.SaveChanges();
        }
}

我尝试使用

AddTransient
AddSingleton
,但这没有解决。

c# .net entity-framework
1个回答
0
投票

这几乎肯定是第一种情况下重复读取的 DbContext 的范围涵盖更新数据的第二个进程的操作,因此当您再次获取记录时,您只是获取跟踪缓存中的内容.

我不知道这一行的意义是什么:

var context = factory.CreateDbContext();

这可能只是为了检查您是否可以实例化 DbContext,但如果将该引用注入到任何地方,它将被视为 Singleton,这不太好。

我强烈建议的下一件事是摆脱 BaseRepository。这是一个通用存储库模式,是 EF 的反模式。查看代码,它是 DbContext 上的一个贫血的外观。只需使用 DbContext 即可。在处理生命周期范围内注入的 DbContext 时,您也不希望代码处理容器提供的引用,这是容器的工作,除非您已将引用定义为瞬态且由外部拥有。如果服务/存储库的范围较长,则将 DbContext 注册更改为 Transient 将无济于事。当容器构造这些服务时,它将解析 DbContext,Transient 将确保它们每个都获得自己的 DbContext 实例,但该实例与引用类一样长。

问题的核心:EF 的跟踪缓存。默认情况下使用此选项,以便 EF 可以跟踪对实体所做的更改,并确保对同一实体的多个请求收到相同的实例。这在处理更新场景时非常有用,但在读取您期望可能由其他进程在后台修改的数据时,就会对您不利。对于您想要确保获取最新数据的读取操作,并且由于您没有编辑该数据,因此不需要跟踪任何更改,请在查询中使用

AsNoTracking()

例如读取ItemCarts的当前数据状态:

var carts = await ItemCarts
    .AsNoTracking()
    .Where(x => /* criteria */)
    .ToListAsync();

此查询将始终从数据库中提取数据状态。检索到的实体不会放入跟踪缓存中(使其更快一些),并且也不会读取可能恰好位于跟踪缓存中的任何实体。

© www.soinside.com 2019 - 2024. All rights reserved.