【问题标题】:How to load data into InMemory database on startup in Asp.Net Core API?如何在 Asp.Net Core API 启动时将数据加载到 InMemory 数据库中?
【发布时间】:2021-02-04 08:00:11
【问题描述】:

我正在研究 Asp.Net Core 3.1 API。我在 SQL Server 数据库中有几张表。

我正在尝试使用 InMemory 数据库,并尝试在应用程序启动时将数据加载到这些表中。

我已经写了下面的代码。

public partial class MyContext : DbContext
{
public MyContext ()
{
}

public MyContext (DbContextOptions<MyContext > options)
    : base(options)
{

}

public virtual DbSet<TestEntity> TestEntity{ get; set; }
...
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    if (!optionsBuilder.IsConfigured)
    {
        optionsBuilder.UseInMemoryDatabase("name=RuleDB");
    }
}

Startup.cs

public void ConfigureServices(IServiceCollection services)
{

    services.AddDbContext<MyContext>(opt => opt.UseInMemoryDatabase("myDbName"));

appsettings.json

"ConnectionStrings": {
  "RuleDB": "Server=tcp:xyz.database.windows.net,1433;Initial Catalog=myDB;Persist Security Info=False;User ID=test;Password=****;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30"
}

当我尝试执行context.TestEntity.ToList(); 时,它没有显示任何记录。

我基本上是在应用程序启动时尝试将数据从我的 SQL Server 数据库加载到我的 InMemory 数据库。

我是否遗漏了任何步骤,这不是一个好方法(我的意思是我应该使用 InMemory Cache 代替 InMemory 数据库)?

【问题讨论】:

  • 如果您首先使用实体​​框架代码,您可以创建负责播种数据的新迁移,您可以调用 migrationBuilder.SQL("insert into table");在 up 方法中。然后确保在启动时应用迁移。
  • @DaveMorrison 我没有使用代码优先方法,它是数据库优先
  • 别担心,我发布了一个我以前使用过的解决方案......希望它对你有帮助!
  • 为什么要从真实数据库中植入内存数据库?内存数据库被视为理想用于单元测试的 Mock,我提供的信息是在启动例程期间播种内存数据库的一种方法,但如果我了解您要实现的目标,我可能能够帮助找到正确的解决方案。
  • @DaveMorrison 这是我最初的问题stackoverflow.com/questions/64451674/…

标签: c# asp.net-core entity-framework-core asp.net-core-3.1 ef-core-3.1


【解决方案1】:

根据您的代码 sn-p,我没有找到您在应用程序启动时将数据添加到内存数据库的位置。所以,我认为问题是相关的。

尝试将以下文章引用到数据库中的种子数据:

Applying Seed Data To The Database

Using EF Core's InMemory Provider To Store A "Database" In Memory

Entity Framework Core InMemory Database

【讨论】:

  • 这样的话,我将不得不为实体中的所有100000条记录编写相同的代码?有没有办法直接播种整个数据库或至少在表级别?
【解决方案2】:

在 StartUp.cs 中,ConfigureServices 引用了

services.AddTransient<IEntityRepository, EntityRepository>();
services.AddTransient<IEntityService, EntityService>();    
services.AddMemoryCache();

添加新的存储库接口。

public interface IEntityRepository
{
    Task<List<Entity>> GetEntity();
}

添加一个封装 DbContext 的新类,并实现接口

public class EntityRepository : IEntityRepository
{
    private readonly DbContext _dbContext;
    
    public(EntityRepository dbContext){
        _dbContext = dbContext;
    }
    
    public async Task<List<Entity>> GetEntity()
    {
        return await _dbContext.Entity.ToListAsync();
    }
}

添加另一个名为 IEntityService 的接口

public interface IEntityService
{
    Task<List<Entity>> GetEntity();
}

添加另一个名为 EntityService 的类,封装缓存和存储库调用。

public class EntityService : IEntityService
{
    private readonly IEntityRepository _repository;
    private readonly IMemoryCache _cache;
    
    public(EntityService repository, IMemoryCache cache){
        _repository = repository;
        _cache = cache
    }
    
    public async Task<List<Entity>> GetEntity()
    {
        var cacheKey = $"{anything-can-be-user-specific-too}";

        return await _memoryCache.GetOrCreateAsync(cacheKey, x =>
        {
            var entities = _repository.GetEntity().GetAwaiter().GetResult();
            x.SlidingExpiration = TimeSpan.FromSeconds(900);
            x.AbsoluteExpiration = DateTime.Now.AddHours(1);

            return Task.FromResult(entities);
        });
    }
}

我之前举的缓存策略说明,如果10分钟内没有引用缓存(slidingRefresh),就会过期并被移除。这可以与 AbsoluteExpiration 一起使用,以便您可以在假设 1 小时后强制刷新缓存...

现在让 IEntityService 调用您的起点,假设您有一个控制器...

将服务注入控制器,例如

 public class RandomController : ControllerBase
    {
        private readonly IEntityService _entityService;

        public RandomController(IEntityService entityService)
        {
            _entityService = entityService;
        }
        
        [HttpGet]
        [Route("randomroute")]
        public async Task<IActionResult> GetEntities()
        {
            return Ok( await _entityService.GetEntity());
        }
    
    }

应用程序第一次执行时将引用数据库,但是,所有后续调用(直到缓存策略过期)都将引用内存缓存。

现在如果要更改缓存项,可以引入新服务来执行数据库更新,然后通过使缓存键无效来强制更新缓存。

Updating IMemoryCache once an entity has changed

【讨论】:

  • 此解决方案不起作用,您正在尝试向实体添加记录,这不是我要找的
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-01-25
  • 1970-01-01
  • 2011-08-22
  • 2017-10-19
  • 1970-01-01
  • 1970-01-01
  • 2021-01-24
相关资源
最近更新 更多