Как загрузить данные в базу данных InMemory при запуске в Asp.Net Core API?

Я работаю над API Asp.Net Core 3.1. У меня есть несколько таблиц в базе данных 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)?


person vivek nuna    schedule 21.10.2020    source источник
comment
Если вы сначала используете код структуры сущностей, вы можете создать новые миграции, которые отвечают за заполнение данных, вы можете вызвать migrationBuilder.SQL (вставить в таблицу); в методе вверх. затем убедитесь, что миграция применяется при запуске.   -  person Dave Morrison    schedule 21.10.2020
comment
@DaveMorrison Я не использую подход «сначала код», это сначала база данных   -  person vivek nuna    schedule 21.10.2020
comment
Не беспокойтесь, я опубликовал решение, которое использовал раньше... надеюсь, оно вам поможет!   -  person Dave Morrison    schedule 21.10.2020
comment
Почему вы хотите заполнить базу данных в памяти из реальной базы данных? База данных в памяти рассматривается как макет, идеально используемый для модульных тестов, предоставленная мной информация является средством для заполнения базы данных в памяти во время процедуры запуска, но если у меня есть понимание того, чего вы пытаетесь достичь, я могу быть в состоянии помогите с правильным решением.   -  person Dave Morrison    schedule 22.10.2020
comment
@DaveMorrison, это мой оригинальный вопрос stackoverflow.com/questions/64451674/   -  person vivek nuna    schedule 22.10.2020
comment
Почему у вас нет слоя репозитория, который отвечает за получение информации из БД, он возвращает список сущностей в службу, эта служба будет зависеть от IMemoryCache.GetOrCreate, если для определенного ключа кеша нет кэшированного значения затем вы попадаете в репозиторий, чтобы получить результаты и кеш, единственная оставшаяся проблема - это обновление записей в кеше. Я вижу 2 варианта... Элементы в IMemCache имеют короткий срок службы, поэтому вызовы в репо происходят часто. Или, если ваше приложение отвечает за обновления, внедрите IMemCache в репозиторий и обновите после сохранения базы данных?   -  person Dave Morrison    schedule 22.10.2020
comment
@DaveMorrison, не могли бы вы предоставить пример кода?   -  person vivek nuna    schedule 22.10.2020
comment
Да, я обновлю свой ответ.   -  person Dave Morrison    schedule 22.10.2020


Ответы (2)


Согласно вашему фрагменту кода, я не нашел, где вы добавляете данные в базу данных в памяти при запуске приложения. Итак, я предполагаю, что проблема связана с этим.

Попробуйте сослаться на следующие статьи Seed Data to The Database:

Применение исходных данных к базе данных

Использование InMemory Provider EF Core для хранения базы данных в памяти

база данных Entity Framework Core InMemory

person Zhi Lv    schedule 22.10.2020
comment
таким образом, мне придется написать один и тот же код для всех 100000 записей в сущности? Есть ли способ напрямую заполнить всю базу данных или, по крайней мере, на уровне таблицы? - person vivek nuna; 22.10.2020

В 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());
        }
    
    }

при первом запуске приложение будет ссылаться на базу данных, однако все последующие вызовы (до истечения срока действия политики кэширования) будут ссылаться на кэш памяти.

Теперь, если вы хотите изменить кешированный элемент, вы можете ввести новые службы для выполнения обновлений базы данных, а затем принудительно обновить кеш, сделав ключ кеша недействительным.

Обновление IMemoryCache после изменения объекта

person Dave Morrison    schedule 21.10.2020
comment
Это решение не работает, вы пытаетесь добавить записи в сущность, это не то, что я ищу - person vivek nuna; 21.10.2020