我有一种情况,我希望能够访问历史信息,以便回顾性地生成指标或理解过去某些方面的情况,直到现在我一直在存储最新的内容(例如已经应用了所有更新的记录)但现在希望能够转回时间。
在推出自己的解决方案之前:
我不希望记录的消费者能够更改它们,因此任何“更新”都应该通过存储库进行编组,它将创建包含完整内容的新记录。
理想情况下,我想把它转移到SQL后端,所以如果存在模式,我希望与它们保持密切联系。
基本设计思路是:
定义一个接口,比如说IUpdatableRecord:
public interface IUpdatableRecord<K>
{
K Key { get; }
DateTime Updated { get; }
}
使用枚举功能定义存储库:
public class DataRepository : IEnumerable<IUpdateableRecord<K>>
{
// Some internal collection that allows duplicate keys
private IList<IUpdateableRecord<K>> dataStore = ....;
// Some enumerator overloads
public IEnumerator<IUpdateableRecord<K>> GetEnumerator()
{
return dataStore.GetEnumerator();
}
// enumerator for contents as of a specific date-time
public IEnumerator<IUpdateableRecord<K>> GetEnumerator(DateTime refDate)
{
// Group by key (so all versions of a record together)
var groupedByKey = dataStore.GroupBy(r => r.Key);
// Sort the keys within each group for a date/time order
foreach ( var rec in groupedByKey )
{
var sorted = rec.OrderBy(r => r.Updated);
// Ignore updates after the reference date & keep last (or default)
var last = sorted.Where(r => r.Updated < refDate).LastOrDefault();
// yield last record if any
if ( last != null )
{
yield return last;
}
}
}
// code for 'adding/updating' a record.
}
答案 0 :(得分:1)
如果您希望此解决方案使用SQL后端,那么您应该考虑ADO.NET实体框架或Linq-SQL。
您的主要潜在问题是您的枚举器,因此您需要查看一些方法并检查Linq生成的SQL(LinqPad对此有用)并确保其有效。
答案 1 :(得分:0)
您可以在RDBMS中实现一些解决方案;一个是存储给定键值的所有历史值以及'valid-from'和'valid-to'日期的地方。 (这通常用于数据仓库解决方案)。这会使您的查询变得非常复杂,并且很难改进现有的解决方案。我使用的另一种方法是保存作为现有表的副本的历史表,以及一些额外的元数据列;通过强制执行所有更新程序,您可以将更改前记录写入历史记录表。核心表上的任何现有查询都很好,因为它们看到了当前值,但对于历史查询,您可以UNION核心和历史表(通过我的情况下的视图)来提供LINQ对象的源。
在SQL Server中,我对历史记录表使用单独的历史记录模式,以便您可以重复使用表名。
答案 2 :(得分:0)
我后来发现这个问题有一个名称,我想要的数据库类型是'Temporal Database'。
谷歌搜索该术语已经显示了一些非常有用的链接,包括一本完整的(绝版)书籍 从这个类似的discuss.joelonsoftware问题引用。
引用的书籍在此处以免费PDF格式提供:"Developing Time-Oriented Database Applications in SQL"