我正在实现 3 层架构,我的问题是:我应该在哪里调用SaveChanges();
(如果适用(?我应该在哪里创建和提交事务?请阅读整个问题。
在下面的代码中,我只有"读取"操作,但你会得到架构的概念。我正在为这个决定而苦苦挣扎,但我提出了两个选择:
-
在
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(); } } }
-
在工作单元对象的
Core
中创建一个接口。其中将具有保存更改和事务,提交方法。然后在数据层中实现它们,并在Service
类中进行相应的调用。
这是代码。我有 3 个项目:
- Infrstructure(数据( -参考核心和EFCore
- 核心(业务逻辑( -无依赖关系
- Web API(MVC 项目( -参考 Core、Data 和 EFCore
- 核心(没有依赖项,甚至没有对 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);
}
}
- 数据(参考核心项目和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;
}
}
- 网页接口:
[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);
}
}
如果你真的觉得你需要交易,我会尝试在你的服务之上处理它们,这样那些人就不负责处理它们。
执行此操作的一种方法可以是:
-
使用作用域内的
DbContext
。 -
当请求启动或调用服务方法时,使用
Database.BeginTransaction()
创建事务。 -
服务层调用数据层并处理业务逻辑。
-
您的数据层
.SaveChanges()
应用到任何需要的地方。 -
当请求结束或服务方法调用结束时,运行
transaction.Commit()
或transaction.Rollback()
。
在不让您的服务负责的情况下实现这些事务创建/提交/回滚的一种方法是使用过滤器、中间件或拦截器。