我被分配了一个任务来验证使用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)
,其中开发人员期望仅更新一条记录。
答案 0 :(得分:1)
好的,几点。
SaveChanges
会作为事务处理。如果发生任何事情都不会改变进一步使用context.ChangeTracker.Entries()
,您可以从那里获得已更改实体数的计数。因此,这不需要您处理交易。此外,SaveChanges()
只是返回受影响的行数,因此可能无法说明全部情况。
通常,我不喜欢从项目体系结构的角度进行这种检查的想法,它增加了用于动态更改的代码的复杂性,并且只是增加了复杂性而没有带来任何类型的安全性。数据完整性和适当的行为应该使用单元测试而不是那种方法来验证。例如,您可以添加单元测试,以验证被更改的行与您期望的行相同。但这应该是测试代码。不是将要交付生产的代码
但是,如果您需要这样做,请不要使用事务并在更改任何内容之前先对实体进行计数,因为它便宜得多。您甚至可以使用“便宜”的forloop,以便您可以记录哪些实体失败等等。此外,由于我们正在监管开发人员,因此您使用扩展名,这意味着开发人员可以自由使用SaveChanges()
。您应该为DbContext创建一个新的自定义类,并仅公开这两种保存更改的方法。