我一直在寻找一些使用Entity Framework的审计钩子。其中许多都显示旧的/新的价值比较。这对于审计跟踪非常有用,但我正在寻找快照对象。
例如......假设我有一个管理产品的应用程序。产品具有多个属性和关联的其他对象。假设我将对象更改了10次。我们还要说,重要的是我可以查看这些对象更改的屏幕(不是审计跟踪,而是以只读格式实际显示的屏幕)。我感兴趣的是能够为所有这10个更改(取决于我想看到的)检索原始EF产品对象(包含所有相关数据)并使用它来绑定到我的屏幕。
如果我正在使用SQL Server,那么我现在应该为序列化对象使用什么类型(XML,blob等)?这样做有意义吗?
答案 0 :(得分:11)
我们来看看。您需要获取对象图并将其序列化为数据库,格式允许您稍后实现它。我认为有一些工具可以做到这一点。其中之一就是实体框架。
你想做的事情是非常普遍的事情。考虑一个维基引擎。维基需要有一个每个人都看到的提示修订版,以及每个文档的后修订版。维基也需要能够以与显示提示修订版相同的方式显示修订版本。因此,应该为它们使用相同的存储格式。
我建议您允许对所有实体类型进行版本控制。编辑实体类型时,您将编辑提示修订并存储包含先前值的后修订。 (您编辑提示修订而不是插入新提示的原因是因为其他对象(当前未实现为ObjectContext)可能包含指向您希望保留为提示链接的提示的链接,而不是链接到后面的修订版。)
如有必要,可以对SQL Server表进行分区,以便将后端修订存储在不同的文件组中。这将允许您单独备份提示修订版本和修订版本。
答案 1 :(得分:4)
首先,您需要为表添加一组属性:


然后您有几个关于如何存储版本历史记录的选项。您可以


为要存储历史记录的每个主表创建一个新表。该历史表将具有与主表相同的所有字段,但不会强制执行主键和外键。对于每个外键,还存储创建时间版本的引用条目的版本。
或者您可以序列化有关您的实体的所有有趣内容并存储所有序列化的blob对于你想要在一个全局历史表中进行版本化的所有实体(我个人更喜欢第一种方法)。
你好。填写你的历史表?通过更新和删除触发器。


请注意,越来越多的现代系统并没有真正删除任何内容。他们只是将标记的内容视为已删除。如果你想要遵循这种模式(它有几个好处) - 而不是删除添加IsDeleted标志到你的实体(当然你必须在任何地方过滤掉已删除的实体)。


您如何查看自己的历史?只需使用历史表,因为它具有与主表相同的所有属性 - 应该不是问题。但是 - 在扩展外键时 - 确保引用的实体版本与您在历史记录表中存储的版本相同。如果不是 - 您需要转到该引用实体的历史表并在那里获取值。通过这种方式,您可以随时了解实体在当下的样子,包括所有参考文献。


除了上述所有内容之外,您还可以恢复实体的状态任何以前的版本。


请注意,此实现虽然简单,但可能占用一些空间,因为它存储快照,而不仅仅是正在进行的更改。如果您只想存储更改 - 在更新触发器中,您可以检测已更改的字段,序列化它们并存储在全局历史记录表中。这样,您至少可以在用户界面中显示已更改的内容以及由谁更改(尽管您可能无法恢复到以前的版本)。

答案 2 :(得分:3)
在我最近构建的项目中,我们使用了SaveChanges
类中的DbContext
方法。这使我们可以访问ChangeTracker
类的实例。通过拨打ChangeTracker.Entries()
,您可以访问DbEntityEntry
列表。 DbEntityEntry
具有以下有趣的属性和方法:
State
- 是新创建,修改或删除的对象Entity
- 对象的副本CurrentValues
- 已编辑的值OriginalValues
- 原始值的枚举我们为变更集和变更创建了一组POCO,然后我们可以通过EF访问。这使我们的用户可以查看字段级别更改以及日期和负责用户。
答案 3 :(得分:0)
如果您使用的是SQL Server 2016
<或Azure SQL
,请查看时间表(系统版本化的时间表)。
摘自文档:
数据库功能,为提供以下功能提供内置支持 有关在任何时间点存储在表中的数据的信息 不仅限于当前时间正确的数据。 时间性是ANSI SQL 2011中引入的数据库功能。
我写了一个完整的指南,说明如何使用Entity Framework Core在没有任何第三方库的情况下实现它: