跟踪复杂对象图中的变化 [英] Tracking changes in complex object graph

查看:117
本文介绍了跟踪复杂对象图中的变化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我开始考虑在断开应用程序中跟踪复杂对象图中的变化。我已经找到了几个解决方案,但是我想知道是否有最佳实践或者你使用什么解决方案?为什么?我将相同的问题传递给了 MSDN论坛,但我只收到单一答案。我想有更多的答案从其他开发人员的经验中学习。



这个问题与.NET有关,所以对于实现细节的答案我更喜欢与.NET世界相关的答案,但我认为这在其他平台上是一样的。 >

我的案例中的理论问题是在多层架构中定义的(目前不一定是n层),如下所示:




  • 使用ORM处理持久性的存储库层(ORM工具目前无关紧要,但最可能是Entity Framework 4.0或NHibernate)。

  • 表示域对象的纯类(persistent ignorant = POCO,相当于Java world中的POJO)。存储库保留这些类并将其作为查询结果返回。

  • 使用域实体的域服务集。

  • 定义门户到业务逻辑的门面层。在内部,它使用存储库,域服务和域对象。域对象不会公开 - 每个facade方法都使用一组专门的数据传输对象进行参数和返回值。每个门面方法的责任是将域实体转换为DTO,反之亦然。

  • 使用外观图层和DTO的现代Web应用程序 - 我称之为断开连接的应用程序。通常设计在将来会发生变化,因此Facade层将被Web服务层包裹,Web应用程序将消耗服务=>转换到3层(Web,业务逻辑,数据库)。



现在假设其中一个域对象是具有订单详细信息(行)和相关订单的Order。当客户端请求订购订单时,可以修改订单,添加,删除或修改任何订单明细,并添加或删除相关订单。所有这些修改都是通过Web浏览器中的数据完成的 - JavaScript和AJAX。所以当客户端按下保存按钮时,所有的更改都会被单独提交。问题是如何处理这些变化?存储库和ORM工具需要知道哪些实体和关系被修改,插入或删除。我以两个最好的解决方案结束:


  1. 将DTO的初始状态存储在隐藏的字段中(更糟糕的是会话)。当接收到保存更改的请求时,基于接收的数据创建新的DTO,并且基于持久数据创建第二个DTO。合并这两个并跟踪更改。将合并的DTO发送到外观图层,并使用收到的关于更改的信息来正确设置实体图。这需要在域对象中进行一些手动更改跟踪,以便可以从头开始设置更改信息,稍后传递到存储库 - 这是我不太满意的一点。


  2. 不要跟踪DTO的变化。当在门面层中接收到修改后的数据时,创建修改后的实体并从存储库中加载实际状态(通常是数据库的附加查询 - 这是我不太满意的一点) - 合并这两个实体并自动跟踪由ORM工具提供的实体代理的更改(实体框架4.0和NHibernate允许这一点)。并发处理需要特别注意,因为实际状态不一定是初始状态。


你觉得怎么样?你有什么建议?



我知道通过在某些应用程序层使用缓存可以避免其中的一些挑战,但这是我目前不想使用的。 >

我对这个话题的兴趣甚至更远。例如,假设该应用程序进入3层体系结构,并且客户端(Web应用程序)将不会被写入.NET = DTO类中,不能重复使用。跟踪DTO的变化将会更加困难,因为它将要求其他开发团队在其开发工具中正确实施跟踪机制。



我相信这些问题必须解决很多申请,请分享你的经验。

解决方案

这一切都是关于责任的。



(我不知道这是否是你以后的答案 - 让我知道如果不能,我可以更新)。



所以我们在一个系统中有多个层次 - 每个层面负责不同的任务:数据访问,UI,业务逻辑等。当我们以这种方式构建系统时,我们(其中包括)尝试通过制作未来的变化每个组件负责一个任务 - 所以它可以专注于一个任务,并做好。随着时间的推移,系统的修改也变得更加容易,而且改变是重要的。



在考虑DTO时,需要考虑类似的想法 - 如何跟踪变化? 例如。这是我如何处理它:BL负责管理规则和逻辑;考虑到网络的无状态(这是我做大部分工作的地方),我只是不追踪一个对象的状态并明确地查看更改。如果一个用户将数据传回(要保存/更新),我将全部通过,而不用关心改变的内容。



一方面这似乎无效但是由于数据量不大,这并不是问题;另一方面,移动部件不太可能出错,因为这个过程要简单得多。



我如何传回数据? -




  • 我使用DTO(或者也许POCO会更准确);当我在BL和DAL之间交换数据(通过接口/ DI ),数据被交换为一个DTO(或它们的集合)。具体来说,我为单个实例使用一个结构体,并为多个结构体使用一个结构体。


  • DTO是在一个普通的类中定义的,很少依赖。


  • 我故意尝试限制DTO为特定对象创建的数量(如订单) - 但同时我会做出新的如果有一个很好的理由。通常我会有一个胖的DTO,其中包含大部分/所有可用于该对象的数据,我也可能有一个更精简的设计用于集合(列表等)。在这两种情况下,这些DTO是纯粹的返回阅读信息。你必须牢记责任 - 当BL要求数据时,它通常不会同时写回数据;所以DTO是只读的事实更符合与业务规则相适应的干净的界面和体系结构。


  • 我总是为单独的DTO定义插入和更新 - 即使它们具有完全相同的字段。这样可能发生的最糟糕的情况是重复一些trival代码,而不是依赖和多重复用的案例来解开。




最后 - 不要混淆DAL如何与UI的工作方式;让ORM做他们的事情,只因为他们以特定的方式存储数据并不意味着它是唯一的方法。



最重要的是指定有意义的接口你的层层。



管理改变的是BL的工作;让UI以最适合您的用户的方式工作,并让BL了解如何处理此问题,以及DAL(通过您的良好干净的界面与 DI )只是做了它所告诉的。


I started to think about tracking changes in complex object graph in disconnected application. I have already found several solutions but I would like to know if there is any best practice or what solution do you use and why? I passed same question to MSDN forum but I received only single answer. I would like to have more answers to learn from experience of other developers.

This question is related to .NET so for answers with implementation details I prefer answers related to .NET world but I think this is the same on other platforms.

The theoretical problem in my case is defined in multi layered architecture (not necessarily n-tier at the moment) as follows:

  • Layer of repositories using ORM to deal with persistence (ORM tool doesn't matter at the moment but it will most probably be Entity Framework 4.0 or NHibernate).
  • Set of pure classes (persistent ignorant = POCO which is equivalent of POJO in Java world) representing domain objects. Repositories persists those classes and returns them as results of queries.
  • Set of Domain services working with domain entities.
  • Facade layer defining gateway to business logic. Internally it uses repositories, domain services and domain objects. Domain objects are not exposed - each facade method uses set of specialized Data transfer objects for parameter and return value. It is responsibility of each facade method to transform domain entity to DTO and vice-versa.
  • Modern web application which uses facade layer and DTOs - I call this disconnected application. Generally design can change in future so that Facade layer will be wrapped by web service layer and web application will consume that services => transition to 3-tier (web, business logic, database).

Now suppose that one of the domain object is Order which has Order details (lines) and related Orders. When the client requests Order for editation it can modify Order, add, remove or modify any Order detail and add or remove related Orders. All these modifications are done on data in the web browser - javascript and AJAX. So all changes are submited in single shot when client pushes the save button. The question is how to handle these changes? Repository and ORM tool need to know which entities and relationships were modified, inserted or deleted. I ended with two "best" solutions:

  1. Store initial state of DTO in hidden field (in worse case to session). When receiving request to save changes create new DTO based on received data and second DTO based on persisted Data. Merge those two and track changes. Send merged DTO to facade layer and use received information about changes to properly set up entity graph. This requires some manual change tracking in domain object so that change information can be set up from scratch and later on passed to repository - this is the point I am not very happy with.

  2. Do not track changes in DTO at all. When receiving modified data in facade layer create modified entity and load actual state from repository (generally additional query to database - this is the point I am not very happy with) - merge these two entities and automatically track changes by entity proxy provided by ORM tool (Entity framework 4.0 and NHibernate allow this). Special care is needed for concurrency handling because actual state does not have to be the initial state.

What do you think about that? What do you recommend?

I know that some of these challenges can be avoided by using caching on some application layers but that is something I don't want to use at the moment.

My interest in this topic goes even futher. For example suppose that application goes to 3-tier architecture and client (web application) will not be written in .NET = DTO classes can't be reused. Tracking changes on DTO will than be much harder because it will require other development team to properly implement tracking mechanism in their development tools.

I believe these problems have to be solved in plenty of applications, please share you experience.

解决方案

It's all about responsibility.

(I'm not sure if this is the sort of answer you're after - let me know if it's not so I can update it).

So we have multiple layers in a system - each is responsible for a different task: data access, UI, business logic, etc. When we architect a system in this way we are (amongst other things) trying to make future change easy by making each component responsible for one task - so it can focus on that one task and do it well. It also makes it easier to modify the system as time passes and change is neeed.

Similar thoughts need to be in mind when considering the DTO - "how to track changes?" for example. Here's how I approach it: The BL is responsible for managing rules and logic; given the stateless nature of the web (which is where I do most of my work) I'm just not tracking the state of an object and looking explicitly for changes. If a user is passing data back (to be saved / updated) I'll pass the whole lot back without caring what's been changed.

One one hand this might seem inefficient but as the amounts of data aren't vast it's just not an issue; on the flipside, there's less "moving parts" less can go wrong as the process is much simpler.

How I pass the data back? -

  • I use DTO's (or perhaps POCO's would be more accurate); when I exchange data between the BL and DAL (via interfaces / DI) the data is exchanged as a DTO (or collection of them). Specifically, I'm using a struct for a single instance and a collection of these structs for multiple.

  • The DTO's are defined in a common class that has very few dependencies.

  • I deliberately try to limit the number of DTO's a create for a specific object (like "Order") - but at the same time I'll make new ones if there is a good reason. Typically I'll have a "fat" DTO which contains most / all of the data available for that object, I'll also probably have a much leaner one that's designed to be used in collections (for lists, etc). In both cases these DTO's are pureyl for returning info for "reading". You have to keep the responsibilities in mind - when the BL asks for data it's usually not trying to write data back at the same time; so the fact that the DTO is "read only" is more about conforming to a clean interface and architecture than a business rule.

  • I always define seperate DTO's for Inserting and Updating - even if they share exactly the same fields. This way the worst that can happen is duplication of some trival code - as opposed to having dependancies and multiple re-use cases to untangle.

Finally - don't confuse how the DAL works with how the UI does; Let ORM's do their thing, just because they store the data in a given way doesn't mean it's the only way.

The most important thing is to specify meaningful interfaces between your layers.

Managing what's changed is the job of the BL; let the UI work in a way that's best for your users and let the BL figure out how it wants to deal with that, and the DAL (via your nice clean interface with DI) just does what it's told.

这篇关于跟踪复杂对象图中的变化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆