База данных в памяти не сохраняет данные - PullRequest
0 голосов
/ 22 мая 2018

У меня есть простое веб-приложение с угловым на стороне клиента и основным веб-API asp.net на стороне сервера.Я использую InMemoryDatabase

services.AddDbContext<ItemsContext>(options => options.UseInMemoryDatabase("ItemsDB"));

для хранения данных для простоты разработки.Но я столкнулся с проблемой с этим.У меня есть один контроллер на web-api для ответа на запросы пользователей:

[Route("api/[controller]")]
public class ItemsController : Controller
{
    private readonly IApiService apiService;

    public ItemsController(IApiService apiService)//using DI from Startup.cs
    {
       this.apiService = apiService;
    }

    [HttpPost, Route("addItem")]
    public async Task<Response> Add([FromBody]Item item)
    {
        return await apiService.Add(item);
    }

    [HttpDelete("{id}")]
    public async Task<Response> Delete(int id)
    {
        return await apiService.Delete(id);
    }

    [HttpPut]
    public async Task<Response> Put([FromBody]Item item)
    {
         return await apiService.Put(item);
    }
}

и следующие конфигурации Startup.cs:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();
    services.AddDbContext<ItemsContext>(options => options.UseInMemoryDatabase("ItemsDB"));
    services.AddSingleton<IUnitOfWork, UnitOfWork>(provider => {
        var context = services.BuildServiceProvider().GetService<ItemsContext>();
        return new UnitOfWork(context);
    });
    services.AddSingleton<IApiService, ApiService>(provider => {
        return new ApiService(services);
    });
}

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

public class ApiService: IApiService
{
    private readonly IUnitOfWork database;
    private readonly IServiceProvider provider;

    public ApiService(IServiceCollection serviceCollection)
    {
        provider = serviceCollection.BuildServiceProvider();
    }

    public IUnitOfWork Database 
    { 
        get 
        {
            return provider.GetService<IUnitOfWork>();
        }
    }

    public async Task<Response> Add(Item item)
    {
        Database.Items.Add(item);
        await Database.SaveAsync();

        var id = Database.Items.LastItem().Id;
        return new Response() { Result = true, ItemId = id };
    }

    public async Task<Response> Delete(int id)
    {
        var item = await db.Items.Find(id);
        Database.Items.Remove(item);
        await Database.SaveAsync();

        return new Response() { Result = true };
    }

    public async Task<Response> Put(Item item)
    {
        Database.Items.Update(item);
        await Database.SaveAsync();
        return new Response() { Result = true };
    }
}

Обновление: реализация UnitOfWork:

 public class UnitOfWork: IUnitOfWork
{
    private readonly DbContext context;
    private IRepository<Item> itemsRepository;

    public UnitOfWork(DbContext dbContext)
    {
        context = dbContext;
    }

    public IRepository<Item> Items
    {
        get
        {
            return itemsRepository ?? (itemsRepository = new Repository<Item>(context));
        }
    }

    public void Dispose()
    {
        context.Dispose();
    }

    public void Save()
    {
        context.SaveChanges();
    }

    public async Task SaveAsync()
    {
        await context.SaveChangesAsync();
    }
}

1 Ответ

0 голосов
/ 22 мая 2018

В вашем коде есть несколько серьезных проблем, давайте их рассмотрим.

  1. services.AddDbContext добавляет службу Scoped, что означает, что экземпляры будут создаваться и удаляться при каждом запросе.services.AddSingleton добавляет службу Singleton, поэтому будет создан только один экземпляр.Вы не можете добавить сервис с заданной областью к одноэлементному сервису, потому что ссылка, которую использует одноэлементный сервис, будет удалена, и у вас получится удаленный контекст.
  2. Этот код:

    return provider.GetService<IUnitOfWork>();
    

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

  3. Вот эта часть, из которой ваш вопрос фактически возникает:

    Database.SaveAsync();
    

    Вы вызываете асинхронную функцию, а не await, чтобы завершить ее.Задача может закончиться или нет, может выдать ошибку или нет, вы никогда не узнаете, что произошло.

Самое лучшее, что всего этого можно избежать, если люди прекратят попыткисоздайте шаблон «Единица работы + репозиторий» поверх еще одной единицы «Работа и репозиторий» .Entity Framework Core уже реализует это:

DbContext => Unit of Work
DbSet => Repository (generic)

Зачем вам нужна еще одна абстракция?Вы действительно когда-нибудь выбросите EF Core из проекта, чтобы оправдать затраты на обслуживание вашего кода?

Весь код вопроса мог бы быть таким:

[Route("api/[controller]")]
public class ItemsController : Controller
{
    private readonly YourContext _context;

    public ItemsController(YourContext context)
    {
       _context = context;
    }

    [HttpPost]
    public async Task<IActionResult> Add([FromBody]Item item)
    {
        context.Items.Add(item);
        await context.SaveChangesAsync();

        return Ok(item.Id);
    }

    [HttpDelete("{id}")]
    public async Task<IActionResult> Delete(int id)
    {
        context.Items.Remove(item);
        await context.SaveChangesAsync();

        return Ok();
    }

    [HttpPut]
    public async Task<IActionResult> Put([FromBody]Item item)
    {
        context.Items.Update(item);
        await context.SaveChangesAsync();

        return Ok();
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...