【问题标题】:Implementing object change tracking in an N-Tier WCF MVC application在 N 层 WCF MVC 应用程序中实现对象更改跟踪
【发布时间】:2013-07-20 16:43:28
【问题描述】:

我在网上看到的大多数示例都显示了 WinForms/WPF 上下文中的对象更改跟踪。或者,如果它在网络上,则使用连接的对象,因此可以跟踪对每个对象所做的更改。

在我的场景中,对象一旦离开数据层就会断开连接(映射到 WCF 中的业务对象,并映射到 MVC 应用程序上的 DTO)

当用户对 MVC 上的对象进行更改(例如,更改 1 个字段属性)时,我如何将更改从视图发送到数据库?

我想要一个审核表,用于保存对特定对象所做的更改。我要保存的是对象的前后值,仅用于我们修改的属性

我能想到几种方法来做到这一点

1) 为 MVC 层(或 javascript?)中的所有模型的每个属性实现一个 IsDirty 标志。将该信息一直传播到服务层,最后是数据层。

2) 在服务层中拥有这种更改跟踪机制会很棒,但是在从 MVC 传回修改后的值之后,我将如何跟踪“原始”值?

3) 数据库触发器?但我不确定如何开始。这甚至可能吗?

对于 n 层 mvc-wcf 解决方案,是否有任何已知的对象更改跟踪实现?

审计表示例:

Audit table

Id              Object         Property         OldValue                NewValue
--------------------------------------------------------------------------------------
1               Customer       Name             Bob                     Joe
2               Customer       Age              21                      22

【问题讨论】:

  • +1 当用户对 MVC 上的对象进行更改(例如,更改 1 个字段属性)时,我如何将更改从视图发送到数据库? 你能解释一下吗?
  • 为更清晰而编辑
  • 只需映射回 ORM 类(实体框架?)并调用 SaveChanges()。你有什么问题?
  • @The8thBit :这意味着在运行时,每当特定对象的值发生变化时...,您想通过保存在数据库中来跟踪它?
  • 我想将 的前后值保存到对象审计表中

标签: c# asp.net-mvc inotifypropertychanged n-tier-architecture change-tracking


【解决方案1】:

您的问题分为两部分:

  1. 如何在 MVC 中实现:

通常的方式:您将更改发送回服务器,控制器处理它们等等。 在您的用例中,这并没有什么不寻常的地方,它要求改变 MVC 通常的工作方式。 对于您的用例场景,最好将更改编码为单独的更改操作,而不是作为修改的对象,如果您需要使用反射来找出用户进行了哪些更改。

  1. 如何在数据库上做: 这可能是您想要的问题:

首先远离 ORM 框架,生活太复杂了。

在保存操作的最后一步,您应该有以下信息:

  • 需要更改的对象和字段及其新值。

您需要跟踪以下信息:

  • 您打算在数据库中修改的对象的最后一次更改是什么。

这可以从 Audit 表中获取,需要保存在 Session(或类似 Session 的对象)中。

那么你需要在一个事务中做如下操作:

  • 从数据库中获取正在修改的对象的最后一次更改。
  • 如果对象发生变化则中止,并通知用户发生碰撞。
  • 如果不获取正在更改的字段的当前值。
  • 保存新值。
  • 更新审核表。

为此,我将使用存储过程来减少流程的繁琐,并更好地分离数据库代码和应用程​​序代码之间的关注点。

【讨论】:

  • 如何跟踪我打算在数据库中修改的对象的更改?这是否建议我在 MVC 层的 ViewModel 中一直实现 isDirty 标志,并将其一直传递回数据层?
  • 1.不,您已经有了审计,如果您需要更改客户 ID = 12,只需在审计跟踪中记录对该对象的最后修改的 ID。 2. 对于您的用例,您需要有一种方法来确定哪些字段已更改。这可能是一个脏标志,但更有效的是拥有一个更改日志:一个封装更改的对象,例如客户:10,字段:名称,值:Bob。这些将直接转化为数据库中的更改。
  • 一个问题。你说“首先远离 ORM 框架,生活太复杂了。” - 你如何坚持改变?自己写sql?还是使用数据表?
  • 我个人更喜欢使用像 Dapper 这样的 micro-orm,并使用存储过程来保存实际的 SQL。这样,数据库和应用程序之间仍然有一个接口,数据库专家实际上可以在他们自己的环境中优化查询。
【解决方案2】:

此问题的可能解决方案在很大程度上取决于您在用户编辑数据时允许对数据库进行哪些更改。

换句话说,一旦它“离开”数据库,它是专门为用户锁定的,还是其他用户或进程可以同时更新它?

例如,如果用户可以获取数据并在上面坐了几个小时或几天,但数据库继续允许更新数据,那么您真的想跟踪用户对数据所做的更改当前在数据库中的版本,而不是用户对他们正在查看的数据所做的更改。

我们处理这种情况的方式是启动一个事务,读取整个现有对象,然后使用反射比较旧值和新值,将更改记录到审计日志中。这在处理嵌套记录时会有点复杂,但值得花时间去实现。

另一方面,如果不允许其他用户或进程更改数据,那么您有几个不同的选项,它们在复杂性、数据存储和对现有数据结构的影响方面各不相同。

例如,您可以修改每个类中的每个属性,以记录它何时发生变化,并在类中保持这些变化的运行记录(显然,基类实现在这里有很大帮助)。

但是,根据您捕获用户更改的时间点(例如,每次他们更新表单中的字段),这可能会生成大量无用的日志信息,因为您可能只想知道从数据库的角度,而不是从 UI 的角度,发生了什么变化。

您还可以深度克隆对象并将其传递到各个层。然后,当需要确定发生了什么变化时,您可以再次使用反射。但是,根据您的业务对象的大小,这种方法可能会导致严重的性能损失,因为必须通过网络传输完整的副本并与原始记录一起保留。

您还可以实施与“编辑时允许更新”方法相同的方法。在我看来,这是最简洁的解决方案,因为原始数据不必与编辑后的数据一起移动,没有篡改原始数据的可能性,并且它支持众多客户端,而无需支持 UI 中的更改跟踪级别。

【讨论】:

  • 不,没有任何东西被锁定。其他用户可以编辑相同的数据。
  • 好的,那么我绝对建议您在用于更新记录的同一事务开始时检索原始记录。我们在一个系统中大量使用这一点,该系统有数千个同时通过网络客户端、移动设备、电子邮件、win forms 应用程序等提交数据的用户。来自所有客户端的所有数据都通过应用程序层中的一个阻塞点,这是我们按照描述执行审计的地方。
  • 你是说,我应该这样做:例如,用户想要编辑客户的数据。 1)从服务(WCF)层检索客户数据。 2)更改1个属性(例如,名称) 3)保存时(将数据发送回服务层),再次检索记录并进行比较?
  • 是的,完全正确。问题是,即使该用户更改了 1 个属性,如果其他 4 个用户更改了不同的属性,并且您用用户在其屏幕上查看的属性覆盖了所有这些属性,从技术上讲,最后一个用户已经更新了所有这些属性,不仅仅是他们在 UI 中更改的那个。
猜你喜欢
  • 2011-08-22
  • 1970-01-01
  • 1970-01-01
  • 2012-01-02
  • 1970-01-01
  • 1970-01-01
  • 2011-11-27
  • 2010-10-28
  • 2011-10-26
相关资源
最近更新 更多