我正在实施数据库审计跟踪,通过我的 Web API 项目中的控制器执行的 CRUD 操作将序列化新旧 poco 并存储它们的值以供以后检索(历史、回滚等)。
当我完成所有工作时,我不喜欢它在 POST 期间让我的控制器看起来如何,因为我最终不得不调用SaveChanges()
两次,一次是为了获取插入实体的 ID,然后再次提交需要知道的审计记录那个身份证。
我着手将项目(仍处于起步阶段)转换为使用序列而不是标识列。这有一个额外的好处,那就是进一步将我从 SQL Server 中抽象出来,虽然这不是一个真正的问题,但它也允许我减少提交的数量,并让我将逻辑从控制器中拉出并将其填充到我的服务层中从存储库中抽象出我的控制器,让我在这个“shim”层中像审计一样工作。
一旦Sequence
创建了对象和一个存储过程来公开它,我就创建了以下类:
public class SequentialIdProvider : ISequentialIdProvider
{
private readonly IService<SequenceValue> _sequenceValueService;
public SequentialIdProvider(IService<SequenceValue> sequenceValueService)
{
_sequenceValueService = sequenceValueService;
}
public int GetNextId()
{
var value = _sequenceValueService.SelectQuery("GetSequenceIds @numberOfIds", new SqlParameter("numberOfIds", SqlDbType.Int) { Value = 1 }).ToList();
if (value.First() == null)
{
throw new Exception("Unable to retrieve the next id's from the sequence.");
}
return value.First().FirstValue;
}
public IList<int> GetNextIds(int numberOfIds)
{
var values = _sequenceValueService.SelectQuery("GetSequenceIds @numberOfIds", new SqlParameter("numberOfIds", SqlDbType.Int) { Value = numberOfIds }).ToList();
if (values.First() == null)
{
throw new Exception("Unable to retrieve the next id's from the sequence.");
}
var list = new List<int>();
for (var i = values.First().FirstValue; i <= values.First().LastValue; i++)
{
list.Add(i);
}
return list;
}
}
它简单地提供了两种获取 ID 的方法,一个和一个范围。
在第一组单元测试中这一切都很好,但是当我开始在现实世界的场景中测试它时,我很快意识到单次调用GetNextId()
将在该上下文的生命周期内返回相同的值,直到SaveChanges()
被调用,因此否定任何真正的好处。
我不确定是否有办法绕过创建第二个上下文(不是选项)或使用老式 ADO.NET 并进行直接 SQL 调用并使用 AutoMapper 来获得相同的最终结果。这些都不吸引我,所以我希望其他人有一个想法。