我正在实施数据库审计跟踪,通过我的Web API项目中的控制器执行的CRUD操作将序列化旧的和新的poco,并存储它们的值以供以后检索(历史记录,回滚等)。
当我把所有东西都弄好之后,我不喜欢它在POST期间使我的控制器看起来如此。这是因为我最终不得不调用SaveChanges()
两次,一次是为了获取已插入实体的ID,然后再提交需要知道该ID的审计记录。
我开始将该项目(仍处于初级阶段)转换为使用序列而不是标识列。这具有进一步使我与SQL Server进行抽象化的附加优点,尽管这并不是真正的问题,但它还允许我减少提交次数,并让我将那个逻辑从控制器中提取出来并将其放入我的服务层中,从而使我的控制器从存储库进行抽象化,并允许我在该“垫片”层中执行此类审计工作。
一旦创建了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的方式,分别是单个ID和一组ID。
这在第一批单元测试中表现得非常出色,但当我开始在真实环境中进行测试时,很快就意识到对 GetNextId()
的单次调用将为该上下文的生命周期返回相同的值,直到调用 SaveChanges()
,因此没有任何实际益处。
除了创建第二个上下文(不可选项)或使用老式 ADO.NET 进行直接 SQL 调用并使用 AutoMapper 来获得相同的净结果之外,我不确定是否有其他方法解决这个问题。这两种方法都不吸引我,所以我希望有人能给我一个想法。