实体框架核心验证SaveChanges计数

时间:2020-09-16 14:44:39

标签: asp.net-core entity-framework-core asp.net-core-3.1 ef-core-3.1 entity-framework-core-3.1

我被分配了一个任务来验证使用SaveChanges()完成的更改的数量。 预计开发人员应该在调用SaveChanges()时事先知道要更改多少记录

要实现它,我为DbContext创建了一个扩展方法,称为SaveChangesAndVerify(int expectedChangeCount),在这里我正在使用事务并将此参数与返回值SaveChanges()相等。 如果值匹配,则提交事务;如果值不匹配,则事务回滚。

请检查下面的代码,让我知道它是否可以工作以及是否需要考虑任何因素。另外,有没有更好的方法

public static class DbContextExtensions
{
    public static int SaveChangesAndVerify(this DbContext context, int expectedChangeCount)
    {
        context.Database.BeginTransaction();
        var actualChangeCount = context.SaveChanges();
        if (actualChangeCount == expectedChangeCount)
        {
            context.Database.CommitTransaction();
            return actualChangeCount;
        }
        else
        {
            context.Database.RollbackTransaction();
            throw new DbUpdateException($"Expected count {expectedChangeCount} did not match actual count {actualChangeCount} while saving the changes.");
        }
    }

    public static async Task<int> SaveChangesAndVerifyAsync(this DbContext context, int expectedChangeCount, CancellationToken cancellationToken = default)
    {
        await context.Database.BeginTransactionAsync();
        var actualChangeCount = await context.SaveChangesAsync();
        if(actualChangeCount == expectedChangeCount)
        {
            context.Database.CommitTransaction();
            return actualChangeCount;
        }
        else
        {
            context.Database.RollbackTransaction();
            throw new DbUpdateException($"Expected count {expectedChangeCount} did not match actual count {actualChangeCount} while saving the changes.");
        }
    }
}

示例用法类似于context.SaveChangesAndVerify(1),其中开发人员期望仅更新一条记录。

1 个答案:

答案 0 :(得分:1)

好的,几点。

  • 除非您将其禁用,否则SaveChanges会作为事务处理。如果发生任何事情都不会改变

进一步使用context.ChangeTracker.Entries(),您可以从那里获得已更改实体数的计数。因此,这不需要您处理交易。此外,SaveChanges()只是返回受影响的行数,因此可能无法说明全部情况。

通常,我不喜欢从项目体系结构的角度进行这种检查的想法,它增加了用于动态更改的代码的复杂性,并且只是增加了复杂性而没有带来任何类型的安全性。数据完整性和适当的行为应该使用单元测试而不是那种方法来验证。例如,您可以添加单元测试,以验证被更改的行与您期望的行相同。但这应该是测试代码。不是将要交付生产的代码

但是,如果您需要这样做,请不要使用事务并在更改任何内容之前先对实体进行计数,因为它便宜得多。您甚至可以使用“便宜”的forloop,以便您可以记录哪些实体失败等等。此外,由于我们正在监管开发人员,因此您使用扩展名,这意味着开发人员可以自由使用SaveChanges()。您应该为DbContext创建一个新的自定义类,并仅公开这两种保存更改的方法。