用于收集时间/更新感知的枚举器
我有一种情况,我希望能够访问历史信息,以便回顾性地生成指标或了解过去某个时刻的情况,到目前为止,我一直在存储最新的内容(例如带有曾经应用过的所有更新),但现在希望能够时光倒流。
在推出我自己的解决方案之前:
- 还有其他东西已经存在吗?
- 这是标准模式吗?
- 我在哪里可能会遇到问题?
我不期望记录的使用者能够更改它们,因此任何“更新”都应该通过存储库进行整理,并且它将创建包含完整内容的新记录。
理想情况下,我想将其移至 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.
}
I have a situation where I want to be able to access historical information in order to retrospectively generate metrics or understand the way things stood at a point in the past, up until now I have been storing the most-recent content (e.g. the record with all of the updates ever applied) but would now like to be able to turn back the clock.
Before rolling my own solution:
- Does something else already exist?
- Is this a standard pattern?
- Where am I likely to hit problems?
I'm not expecting consumers of the records to be able to change them, so any 'updates' should be marshalled through the repository and it will create new records containing the full content.
Ideally I'd like to move this over to an SQL backend, so if patterns exist there I'd like to remain close to them.
Basic Design thoughts are:
Define an interface, say IUpdatableRecord:
public interface IUpdatableRecord<K>
{
K Key { get; }
DateTime Updated { get; }
}
Define a repository with enumeration capability:
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.
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
如果您希望此解决方案利用 SQL 后端,那么您应该考虑 ADO.NET 实体框架或 Linq-SQL。
您的主要潜在问题是您的枚举器,因此您需要查看多种方法并检查 Linq (LinqPad 对此很有好处)并确保其高效。
If you want this solution to utilise an SQL backnd, then you should consider either the ADO.NET Entity Framework or Linq-SQL.
Your main potential problem is your Enumerator, so you's need to look at a number of approaches and check the SQL being generated by Linq (LinqPad is good for this) and make sure its efficient.
您可以在 RDBMS 中实施多种解决方案;一种是存储给定键值的所有历史值以及“有效起始日期”和“有效截止日期”的位置。 (这通常用于数据仓库解决方案)。这会使您的查询变得相当复杂,并且对现有解决方案进行改造非常痛苦。我使用的另一种方法是保存作为现有表副本的历史表,以及一些额外的元数据列;通过过程强制所有更新,您可以将更改前的记录写入历史表。核心表上的任何现有查询都可以,因为它们可以看到当前值,但对于历史查询,您可以联合核心表和历史表(在我的例子中通过视图)来提供 LINQ 对象的源。
在 SQL Server 中,我对历史表使用单独的历史模式,以便您可以重复使用表名称。
There are a couple of solutions you can impelemt in an RDBMS; one is where you store all the historical values for a given key value along with a 'valid-from' and a 'valid-to' date. (This is commonly used in data warehousing solutions). This can complicate your queries quite a lot and is a pain to retrofit to an exisiting solution. One other way I have used is to hold history tables that are replicas of exisiting tables, plus a few extra metadata columns; by forcing all updates through procedures, you can write the pre-change record to the history table. Any existing queries on the core tables are fine because they see the current value, but for historical queries you can UNION the Core and history tables (via a view in my case) to provide the source for your LINQ objects.
In SQL Server, I use a seperate History schema for the history tables so you can re-use the table names.
我随后发现这个问题有一个名字,我想要的数据库类型是 “时态数据库”。
谷歌搜索这个术语显示了一些非常有用的链接,包括一本完整的(绝版)书
引用自此类似的 discuss.joelonsoftware 问题。
所引用的书籍可在此处以免费 PDF 形式提供:“开发面向时间的数据库应用程序在 SQL 中”
I have subsequently discovered that this problem has a name, the type of database I wanted is a 'Temporal Database'.
Googling the term has shown some very useful links, including a complete (out of print) book
referenced from this discuss.joelonsoftware question that is similar.
The book referenced, is available as a free PDF here: "Developing Time-Oriented Database Applications in SQL"