内存数据库不保存数据

Art*_*kov 1 c# entity-framework-core asp.net-core

我有一个简单的Web应用程序,在客户端具有angular,在服务器端具有asp.net核心web-api。我使用InMemoryDatabase

services.AddDbContext<ItemsContext>(options => options.UseInMemoryDatabase("ItemsDB"));
Run Code Online (Sandbox Code Playgroud)

存储数据以简化开发。但是我遇到了一个问题。我在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);
    }
}
Run Code Online (Sandbox Code Playgroud)

以及以下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);
    });
}
Run Code Online (Sandbox Code Playgroud)

问题是,当我添加新项目时,一切都很好...但是随后我发布了另一个删除该项目的请求,这可能表明根本没有这样的项目,或者有时它可能将其删除了...所以换句话说,数据库存在,然后消失,我不确定何时。这是参考上面的一些附加代码

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 };
    }
}
Run Code Online (Sandbox Code Playgroud)

更新: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();
    }
}
Run Code Online (Sandbox Code Playgroud)

SO *_*ood 5

您的代码有多个严重问题,让我们解决它们。

  1. services.AddDbContext添加了范围服务,这意味着将在每个请求上创建实例并将其处置。services.AddSingleton添加了Singleton服务,因此将仅创建一个实例。您不能将范围服务添加到单项服务中,因为单项服务使用的引用将被处置,并且最终将获得处置上下文。
  2. 这段代码:

    return provider.GetService<IUnitOfWork>();
    
    Run Code Online (Sandbox Code Playgroud)

    表示服务定位器反模式。如您所料,您想避免使用反模式。我也不知道为什么要让服务构建整个DI容器,也不知道为什么要让服务负责获取其本身所需的依赖关系。

  3. 这部分实际上是您的问题出处:

    Database.SaveAsync();
    
    Run Code Online (Sandbox Code Playgroud)

    您正在调用异步函数,而不是await说它不能完成。该任务可能会完成,也可能不会抛出错误,您将永远不知道发生了什么。

最好的事情是,如果人们停止尝试在另一个工作单元和存储库上创建工作单元+存储库模式,则可以避免所有这些情况。实体框架核心已经实现了这些:

DbContext => Unit of Work
DbSet => Repository (generic)
Run Code Online (Sandbox Code Playgroud)

为什么还要另一个抽象?您是否真的会从项目中舍弃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();
    }
}
Run Code Online (Sandbox Code Playgroud)