我是一名程序员,但也曾担任过档案管理员。作为档案管理员,保存数据非常重要。
在数据操作方面,我经常与同事争论。我不太喜欢CRUD中的U和D。宁愿更新一条记录,我也喜欢添加一条新记录并引用旧记录。这样,您就可以建立变更历史。我也不喜欢删除记录,而是将它们标记为无效。
有这个用语吗?基本上只创建和读取数据?有这种方法的例子吗?
我是一名程序员,但也曾担任过档案管理员。作为档案管理员,保存数据非常重要。
在数据操作方面,我经常与同事争论。我不太喜欢CRUD中的U和D。宁愿更新一条记录,我也喜欢添加一条新记录并引用旧记录。这样,您就可以建立变更历史。我也不喜欢删除记录,而是将它们标记为无效。
有这个用语吗?基本上只创建和读取数据?有这种方法的例子吗?
Answers:
保留更改历史记录的问题之一是,它会使数据库杂乱无章,并且可能极大地增加数据库的大小(取决于使用模式)。因此,一个好主意是将审计跟踪记录存储在单独的位置,并使实际的应用程序表仅填充相关数据。因此,每次应用程序执行CRUD操作时,所做的更改都会记录在审核表中,并且对应用程序表执行CRUD操作(不进行软删除)。
通过使审计跟踪保持独立,可以为您的应用程序提供一个原始数据存储库,以便您与之交互,同时在需要时仍保留更改历史记录。现在,您还可以根据业务需求单独存档审计跟踪,甚至销毁它。
EventSourcing听起来像您可能正在寻找的模式。
让我们以使用一个简单的“ car”对象为例,我们将要跟踪其颜色(后面是伪C#代码)。
public class Car {
public string Color { get; set; }
public Car() { this.Color = "Blue"; }
}
通过CRUD实现,当我们更新汽车的颜色时,先前的颜色将丢失。
MyCar.Color = "Red";
MyCar.Save(); // Persist the update to the database and lose the previous data
对我来说,这种信息丢失听起来像是您最想避免的事情(因此,不喜欢CRUD模式的更新和删除部分)。
如果我们要重写car类以在更新其更改时响应事件,则它可能如下所示:
public class Car {
public string Color { get; private set; } // Cannot be set from outside the class
public void ApplyEvent(CarColorChangedEvent e) {
this.Color = e.Color;
}
}
现在我们将如何更新该对象的颜色?我们可以创建一个CarColorChanged事件!
var evnt = new CarColorChangedEvent("Red");
MyEventStore.save(evnt);
MyCar.ApplyEvent(evnt);
注意到实际模型对象上没有保存吗?这是因为,我们不是直接保留模型,而是保留将模型置于当前状态的事件。这些事件应该是一成不变的。
现在,让我们快进并更改颜色几次:
var evnt = new CarColorChangedEvent("Green");
MyEventStore.save(evnt);
MyCar.ApplyEvent(evnt);
var evnt = new CarColorChangedEvent("Purple");
MyEventStore.save(evnt);
MyCar.ApplyEvent(evnt);
如果我们要查看事件存储(可以是关系数据库,基于文件等),我们将看到与汽车对象有关的一系列事件:
CarColorChangedEvent => Red
CarColorChangedEvent => Green
CarColorChangedEvent => Purple
如果我们想重建该汽车对象,我们可以简单地通过创建一个新的汽车对象并将事件从我们的事件存储区应用到该对象来实现。
var MyCar = new Car();
var events = MyDatabase.SelectEventsForCar("CarIdentifierHere");
foreach(var e in events) {
MyCar.ApplyEvent(e);
}
Console.WriteLine(MyCar.Color); // Purple
通过事件流,我们可以简单地通过创建一个新的汽车对象并仅应用我们想要的事件来将汽车的状态回滚到先前的时间段:
var MyCar = new Car();
var event = MyDatabase.GetFirstEventForCar("CarIdentifierHere");
MyCar.ApplyEvent(e);
Console.WriteLine(MyCar.Color); // Red
事件采购是必经之路,您应该看看Greg Young关于此事的看法。
http://goodenoughsoftware.net/
还可以在他的数据库(事件存储)上查看此演示文稿。您也可以找到其他视频。
http://oredev.org/2012/sessions/a-deep-look-into-the-event-store
除非您特别需要能够搜索已删除的项目,否则我不会寻求“软删除”的答案,但是那样的话您不应该将它们视为已删除而是已存档。我认为术语在这里非常重要。
我也不想维护“版本表”。我见过的所有“版本表” (包括目前正在尝试清除的版本表-由于错误而损坏了7年的数据……即使有历史数据也无法取回。)。。。。因为损坏的原因同样如此)最终会由于代码中的错误而损坏,最终您仍然会丢失数据,因为您永远无法返回并重新创建损坏了的数据。
对于事件源模型,情况并非如此。您始终可以准确地重放用户所做的事情。这是CRUD和事件来源之间非常重要的区别。事件源体系结构将事件保存在事件存储中,而不是数据对象或域模型对象中。一个事件很容易影响多个对象。试想一下购物车解决方案,您可以将购物车中的每个项目转换为实际订单。一个事件影响所有项目对象以及购物车对象,这些对象被转换为订单对象。
如果您在数据库的每个表中都保留了每一行的版本副本,那么想象一下不得不倒退到特定的时间戳的恐怖,更不用说维护该版本表的大量空间和性能开销了。
使用事件源,您只需重播事件直到某个时间点即可轻松倒带。可以使用快照来实现快进,但这只是实现的问题。
但是,我想您会喜欢的真正好处是,因为您对不丢失数据特别感兴趣,因此,如果您发现保存该数据的代码中的错误,则无需回去清理数据(这通常是不可能的,因为数据几乎永远不会完成)。相反,只需修复该错误,然后重播所有事件。然后,您将拥有一个包含正确数据的数据库。
如果进行调试,您有多少次要求用户告诉您他们做了什么...为什么不重播他们所做的然后逐步浏览代码!很漂亮吧。
希望这可以帮助。
是的,它在企业系统中非常普遍,基本上有两种方法:
两种方法的粒度差异很大。例如,如果更改了一个订单项目上的小部件数量,您是否维护整个订单或仅一个项目的历史记录?
一般来说,“双向”是很多额外的工作,只有在您有很多用例(例如“审计师于12月31日获得订单状态”)时才值得。
您可以按照pdr建议使用“ soft-deletes” 。至于更新,您可以保留记录的历史记录,有点像我在这里的答案:https : //dba.stackexchange.com/questions/28195/save-history-editable-data-rdbms/28201#28201 OP希望在其中能够跟踪某些类型数据的所有版本。
没有这4件事基本上不可能完成。Crud意味着创建,读取,更新和删除,因此当您仅尝试读取数据时,可以使用简单的查询来进行查询,但是所有这三件事都附加到数据库的一个和另一个简单概念上
Is there a term for this? Basically only creating and reading data?
当然有:CR; P