通过多个数据库调用重载 CQRS 模式

问题描述 投票:0回答:1

我正在使用 EF core 6.0 开发 .NET 6 项目。该项目是使用 Clean Architecture 和 CQRS 模式构建的。

我的问题比较笼统,我更多地寻求意见而不是直接答案。

想象一下我有一个从数据库中删除用户的命令。我们称之为

DeleteUserByIdCommand
。该命令获取用户 ID 并检查用户是否存在,如果用户存在,则将其删除。

在命令末尾,我调用

context.SaveChanges()
,因此删除实际上发生在数据库中。当我添加另一个命令时,问题就出现了,我们将其命名为
DeleteUsersByIdBulkCommand
。在这个命令中,为了不重复自己,我想使用我现有的
DeleteUserByIdCommand
。新命令采用用户 ID 数组。不过,这样一来,如果我要删除 100 个用户,则
SaveChanges()
和 get 请求将执行 100 次,这对性能来说非常糟糕。

对我来说只有两个简单的选择,我都尝试过:

  1. 只是不要重用
    DeleteUserByIdCommand
    并在新代码中编写新代码。问题是,例如,如果我想扩展命令,比如说从其他数据库或第三方 API 中删除用户,我将不得不在两个地方更改代码。
  2. 另一个解决方案是在
    DeleteUserByIdCommand
    中有一个称为
    ShouldCallSaveChanges
    的属性,它是布尔值。默认情况下它是 true,但是当我从
    DeleteUsersByIdBulkCommand
    调用此命令时,它将设置为 false,并且我将在 foreach 之后执行
    SaveChanges()

我的问题是对于这样的情况是否有一些严格的规则?在这里重复代码是否有问题,或者对于这种情况可能有一些特定的解决方案。我想听听您的意见或您可能有的其他建议:)

performance entity-framework-core query-optimization .net-6.0 cqrs
1个回答
0
投票

这是一般问题的一个例子,“为什么我的批量数据操作语句如此慢?”典型 RDBMS 服务器的一般答案是“因为数据操作的大部分工作发生在提交阶段”。

在纯 SQL 应用程序中,这意味着您应该执行如下所示的一系列操作来有效删除多行:

BEGIN TRANSACTION;
DELETE FROM mytable WHERE whatever;
DELETE FROM mytable WHERE whatever;
DELETE FROM mytable WHERE whatever;
COMMIT;

当您处于事务中时,RDBMS 会对操作进行批处理,当您提交时,它会完成应用这些操作的所有工作。 (这是一个过于简单化的说法,但对于涉及少于数万次操作的几乎所有应用程序来说,这是一个非常有用的心理模型。)

这如何转化为 EF Core? .SaveChanges() 文档是这样说的:

对于大多数数据库提供商来说,SaveChanges 是事务性的。

您提到的代码,通过在每次操作后调用

.SaveChanges()
,隐式地为每个操作执行一个事务。这使得您的代码易于调用者使用。但对于像这样的批量操作来说,它不太适合

foreach (id in arrayOfIds) {
   ctx.DeleteUserById(id);
}

构建代码的最简单方法(无需构建某种神奇的批量模式属性)是始终显式调用 .SaveChanges(),而不是使其隐式。

foreach (var id in arrayOfIds) {
   ctx.DeleteUserById(id);
}
ctx.SaveChanges();

这将与重写代码一样快(除非您要立即删除成千上万的用户)。但你必须记住调用.SaveChanges()。

当我做这些事情时,我实现了一个实现 IDisposable 的更新器类,并在其 Dispose 方法中调用 .SaveChanges。

然后我会做这样的事情。

using (var upd = new MyUpdater()) {
  upd.DeleteUserById (whatever);
  upd.AddUser (whatever);
  upd.ChangeUser (whatever);
 }

当我的 MyUpdater 实例超出使用范围时,它的 .Dispose 方法会被自动调用。如果您想要这样做,这还有一个额外的好处,即使用单个数据库事务来执行一堆不同的操作。

对 .Dispose() 的超出范围的调用总是会发生,即使某处存在异常。

© www.soinside.com 2019 - 2024. All rights reserved.