首页 > 解决方案 > 如何在 ASP.NET Core Web API 中管理 EFCore DbContext 生命周期?

问题描述

我正在实现 3 层架构,我的问题是:我应该在哪里打电话SaveChanges();(如果适用)?我应该在哪里创建和提交事务?请阅读整个问题。

在下面的代码中,我只有“读取”操作,但您会了解架构的概念。我正在为这个决定而苦苦挣扎,但我提出了两个选择:

  1. Core在项目中引用 EFCore 。将 DbContext 注入到Service类中,并通过方法将其注入到数据层。像这样:

    public class ItemService
    {
        private MyContext _ctx;
        private readonly IItemData _itemData;   
    
        public ItemService(IItemData itemData)
        {
            _itemData = itemData;
        }   
    
        public void InjectCtx(MyContext ctx)
        {
            _ctx = ctx;
            _itemData.InjectCtx(_ctx);
        }   
    
        public void Operation(int itemId)
        {
            using (var transaction = _ctx.Database.BeginTransaction())
            {
                //Do something  
    
                _ctx.SaveChanges();
                transaction.Commit();
            }
        }
    }
    
  2. Core在工作单元对象中创建一个接口。其中将具有 SaveChanges 和 Transaction、Commit 方法。然后在数据层实现它们并在Service类中相应地调用。

这是代码。我有3个项目:

- 核心(没有依赖关系,甚至没有对 EFCore 的引用):

public class ItemDto
{
    public int ItemId { get; set; }
    public string Name { get; set; }
}

public interface IItemData
{
    Task<ItemDto> GetItem(int itemId);
}

public class ItemService
{
    private readonly IItemData _itemData;

    public ItemService(IItemData itemData)
    {
        _itemData = itemData;
    }

    public async Task<ItemDto> GetItem(int itemId)
    {
        return await _itemData.GetItem(itemId);
    }
}

- 数据(参考 Core 项目和 EFCore)

   public class ItemData : IItemData
    {
        private readonly MyContext _ctx;

        public ItemData(MyContext ctx)
        {
            _ctx = ctx;
        }

        public async Task<ItemDto> GetItem(int itemId)
        {
            var item = await _ctx.Items
                .Where(i => i.ItemId == itemId)
                .Select(row => new ItemDto()
                {
                    ItemId = row.ItemId,
                    Name = row.ItemName
                })
                .FirstOrDefaultAsync();
            return item;
        }
    }

- 网络 API:

[Route("api/[controller]")]
[ApiController]
public class ItemsController : ControllerBase
{
    private readonly ItemService _itemService;

    public ItemsController(ItemService itemService)
    {
        _itemService = itemService;
    }

    [HttpGet("{itemId}")]
    public async Task<ItemDto> Get(int itemId)
    {
        return await _itemService.GetItem(itemId);
    }
}

标签: c#asp.net-mvcasp.net-coreasp.net-core-mvcentity-framework-core

解决方案


如果您真的觉得您需要交易,我会尝试在您的服务“之上”处理它们,以便那些不负责处理它们。

一种方法可以是:

  • 使用作用域DbContext.

  • 当请求启动或调用服务方法时,使用Database.BeginTransaction().

  • 您的服务层调用您的数据层并处理业务逻辑。

  • 您的数据层适用于.SaveChanges()任何需要的地方。

  • 当请求结束或服务方法调用结束时,运行transaction.Commit()transaction.Rollback().

在不让您的服务对其负责的情况下实现这些事务创建/提交/回滚的一种方法可以是使用过滤器、中间件拦截器


推荐阅读