- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
上下文:在.NET平台上构建智能客户端应用程序,在该平台上您具有包含大量列的复杂数据库模型。自然的应用程序样式是典型的数据驱动的CRUD。在某些情况下,服务器端逻辑也相当合理,验证也有些复杂。您可以完全控制客户端和服务器,因此对互操作性的需求已降至最低。
这个问题有很多细节,对此表示歉意,但这是因为我想为答案设置适当的上下文。
其他一些假设
-在Microsoft世界中并不罕见,大多数以前的应用程序都是使用DataSets编写的,因此它是涉及开发人员的最著名技术。但是,可以说开发人员也非常熟悉面向对象的思想。
-您将需要在客户端和服务器上都运行验证。
-您不会以表格形式显示大多数数据。
-这不是Intranet应用程序,因此您不能过多地考虑带宽
最大的问题:数据集还是对象?
如果您使用数据集,则有一些正面和负面的信息
-积极的一面:从数据库中获取数据,通过网络获取数据以及通过网络以较小的块返回更改的数据方面,您会获得Microsoft的一点支持-因为您只能指定发送更改。发送较少的数据是一件好事,因为可能涉及大量数据。
-负面影响是:在验证,业务逻辑等方面,您将获得程序形式的代码,而您将无法获得面向对象的代码的好处–行为和数据并存,更自然的工作和思考方式您正在做什么,并且可能与验证逻辑有更紧密的联系。您还可以避开将数据集放在网格中的好处,因为这不是常见的用例。
如果您要寻找对象,那是相同的练习,但是涉及的选项更多:
积极因素:将行为和数据结合在一起。验证逻辑更紧密。更容易看到和理解对象之间的关系。更具可读性的代码。更容易进行单元测试。
但是,您还有很多选择和工作要做:
或/映射
-从关系模型到对象的数据获取。或映射器并不那么复杂,并且能够很好地处理它。但这增加了开发时间。
合约对应
-通常将数据从服务器端对象映射到合同对象(可能是DTO的对象)是一种很好的做法。由于此应用程序非常适合CRUD风格的体系结构,因此DTO并不会真正为图片增加太多价值,而只是绘制地图即可。
共享码
-您可以使用共享代码方案,其中包含域数据和逻辑的程序集在客户端和服务器端均可用。紧密耦合,但是如果您具有自然紧密耦合的客户端-服务器应用程序,则不一定坏。
无论您是否选择添加合同层,都有必须通过电线发送的大型对象结构
由于我们同时控制客户端和服务器,因此传输和编码应为基于TCP的二进制编码。那会有所帮助。
对于数据集,您可以选择仅将更改发送回。来回发送整个对象结构可能是性能问题。
发送整个对象结构的一种选择是,以某种方式识别所涉及的更改(创建,更新,删除),并仅发送有关该更改的信息。从理论上讲,将汇总根ID和更改发送到服务器并要求服务器延迟加载汇总根,执行所做的更改,然后再次保存,并不是很困难。但是所涉及的最大复杂性是确定所做的更改。您曾经尝试过这种方法吗?为什么?你到底是怎么做到的?
介绍
确切的UI技术对于这个问题并不是很重要,可以使用WinForms,Silverlight或WPF。让我们假设我们正在使用WPF,因为它是一个新的智能客户端。这意味着我们有两种方式绑定,并且可以正确使用MVVM。
绑定到用户界面中的对象将需要实现INotifyPropertyChanged并在每次更新属性时引发一个事件。您如何解决呢?如果您使用共享代码方案,则可以将其添加到域对象中,但这将涉及在服务器端添加代码和逻辑,而这些代码和逻辑决不该在此处使用。如果您使用合同对象,则分隔会更自然,但这仅仅是增加一层映射而没有太多的附加值。
技术领域
有一些可用的技术可以帮助解决某些问题,但通常会使其他问题复杂化。您是使用它们还是自己重新构建东西?
**
-CSLA是可能的,但是它使单元测试更加困难,并且似乎增加了与数据访问的紧密耦合。它确实可以解决许多问题,但是我个人对此技术没有能力,因此很难说它是否合适。
-Silverlight解决方案可以使用WCF RIA服务,但是肯定存在一些限制。数据大小为一。
-WCF数据服务是另一种快速解决问题的方法,但是REST并没有太大帮助,而且您还缺少RIA Services中提供的验证支持。
摘要
如果您走到了这一步,希望您对我的发展方向有所了解。我试图缩小范围以避免一次谈论所有内容,但是分布式开发很复杂,因此您必须考虑很多部分。
更新资料
谢谢你们的回应!我试图问的问题足够开放,可以回答各种问题,但具体程度足以应付一些不常见的要求。
有不同的考虑因素,各有其优缺点,并且因系统而异。通常,每种方法都会增加寻找解决方案的复杂性。这个问题的重点之一是要获得一些特别的答案,而这些额外的需求并不一定直接适合当今通常是正确的一个答案-使用基于任务的UI。如果您愿意,我不是“ CRUD家伙”。但是由于种种原因(通常是传统的),一些系统非常适合CRUD。
许多业务应用程序有类似的要求,它们的方向不同:
业务相关
-查看:向用户显示数据并更新相同的数据(读取和CUD-创建,更新,删除)
-验证:业务规则
UI相关
-验证:UI规则
-UI更新:特定于仅使UI更新对象更改的代码(INotifyPropertyChanged)
网络相关
-数据大小:您通过网络发送的数据量
数据库相关
-延迟加载
SRP /重用相关
-映射:由多层对象/分离的关注点引起
维护/变更相关
-更改:添加新信息(列/字段)
-代码量
-重用和“改变的理由”
技术局限性
-变更追踪
但是,这些只是一些非常具体的内容。您始终需要知道最重要的“故障”,以及所需的可扩展性,可用性,可扩展性,互操作性,可用性,可维护性和可测试性。
如果我想在大多数情况下归纳一些东西,我会说类似:
客户
-使用MVVM进行分离和可测试性
-在DTO之上创建VM
-在VM中实现INotifyPropertyChanged。
-使用XamlPowerToys,Postsharp或其他一些方法可以帮助解决此问题
-UI中的单独读取和CUD
-使CUDs基于任务,并使用命令或类似命令将这些操作发送到服务器端
服务器
-量身定制每个屏幕的dto
-或使用Ayende在http://msdn.microsoft.com/en-us/magazine/ff796225.aspx中描述的多查询方法
-使用自动映射可避免繁琐,手动且与您要解决的问题完全无关的事情,即映射是
-让域模型主要关注业务操作,包括与CUD相关的操作,而不是读取
-避免增加重用原因的可重用性
-避免封装问题
-(通过启用CQRS样式体系结构,并可能在时间上分别缩放读取和CUD)
-尝试找到一种适合应做的验证方法(请读:http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/02/15/validation-in-a-ddd-world.aspx)
这是否是我在这种特定情况下要采取的方法?
好吧,这就是我想要开始讨论的问题:)但是,这似乎比我希望的要难(你们两个人除外)。
最佳答案
我只能从我们自己的经验中回答。我们尝试了不同的框架(WCF RIA,Ideblade),并得出结论,框架只会使情况变得更糟。我将进一步解释。
首先,您应该忘记CRUD。仅演示应用程序具有CRUD-实际应用程序具有行为。
我不建议在客户端模拟整个实体图。它们是两个分离的关注点。
您应该为每种情况创建量身定制的Dto。例如。假设您有一个OrderSearchView,然后创建一个OrderSearchDto并仅映射所需的字段。在EditOrderView中,您将改为使用EditOrderDto-仅包含所需字段。
我真的不建议在实体和dto之间使用自动映射工具。因为在dto和实体之间通常没有一对一的关系。 dto通常由不同的多个后端实体构建。映射是如此简单,所以我看不到映射框架的意义。而工作不是映射-它是编写单元测试-无论如何(无论有没有映射框架),您都必须这样做。
Dtos应该与客户端技术无关。在dto上实现INotifyPropertyChanged违反了单一职责原则。他们称之为数据传输对象。相反,您可以在客户端上创建演示者。您创建一个EditOrderPresenter,它是EditOrderDto的包装器。因此,dto只是EditOrderPresenter内部的私有成员字段。 Presenter是为在客户端层中进行编辑而量身定制的-因此它通常将实现INotifyPropertyChanged。 EditOrderPresenter通常具有与dto相同的属性名称。
您应该在物理上将客户端验证与服务器端的实体验证分开。当心分享!我认为客户端验证只是GUI的调整-使GUI体验更好。不要在dto和实体之间共享验证代码很重要-它可能比有用性引起更多的麻烦。只要确保您始终在服务器端进行验证,无论在客户端进行哪种验证即可。验证有两种:简单的属性验证和整个实体验证(dto也是如此)。实体验证应仅在状态转换时执行。请查看Jimmy Nilssons域驱动设计以获取背景知识。我不建议使用验证规则引擎-仅使用状态模式。
那更新,插入,删除呢?在我们的实现中,我们使用WCF,并且WCF API只有一种方法:IResponse [] Process(params IRequest [] requests);
这到底是什么意思?这意味着客户端正在向服务器发出一批请求。在服务器端,您为系统中定义的每个请求实现RequestHandler。然后,您返回响应列表。确保Process()方法是一个工作单元(〜一个事务)。这意味着如果批处理中的一个请求失败-所有请求都将失败-这将导致事务回滚-并且不会对数据库造成损害。 (不要在responsehandlers中使用错误代码-而是强制转换异常。)
我建议您窥视Agatha消息传递服务器。戴维·布瑞恩(Davy Brion)关于消息传递层的博客文章很棒。在我们公司中,我们选择实现自己的消息传递服务器-因为我们不需要Agatha提供的所有功能,因此我们对语法进行了一些改进。无论如何,实现消息传递服务器并不是真的很困难-这是一种很好的学习体验。链接http://davybrion.com/blog/
那您要如何处理Dto。好吧,您永远不会更新它们,而是在客户端上更改它们,以便获得对gui的正确反馈。因此,您可以使演示者以正确的顺序跟踪dto(要求)发生的所有事情。这将是您的requestBatch。然后将requestbatch发送到WCF上的process-command-然后将在服务器端“重播”请求并由请求处理程序处理。
这实际上意味着您永远不会更新dto。但是演示者可以在客户端编辑dto,以提供适当的gui反馈。演示者的工作还在于跟踪所有已完成的编辑,以便将它们作为requestbatch(重录的顺序与编辑顺序相同)发回到服务器。
考虑以下情况,您检索一个现有订单,进行编辑,然后将更改提交回数据库。这将导致两个批次,一个批次用于获取订单,另一个批次用于将更改提交回去。
RequestBatch 1:GetOrderByIdRequest
(..然后用户编辑数据..)
第2批需求:
StartEditOrderRequest,状态更改以编辑方式,放松验证
AddConsigneeToOrderRequest
ChangeEarliestETDOnOrderRequest,还不需要验证最新的ETD!
DeleteOrderlineRequest
ChangeNumberOfUnitsOnOrderlineRequest
EndEditOrderRequest,状态更改为原始状态,请在此处执行实体验证!
GetOrderByIdRequest,以便使用最新更改来更新gui。
在服务端,我们使用NHibernate。 Nhibernate使用一级缓存来避免繁重的数据库负载。因此,同一工作单元(requestbatch)中的所有请求都将使用缓存。
每个请求只应包含完成任务的最少数据量。这意味着使用OrderId +其他一些属性而不是整个dto。关于乐观更新,您可以将一些oldValues与请求一起发送-这称为并发集。请记住,并发集通常不包含很多字段。因为在此期间已更改的更新顺序不一定意味着您将有加薪条件。例如。在此期间,如果收货人被其他用户编辑,则添加和订购行并不表示您有加薪条件。
好吧,这不会导致大量的工作。当然,您将拥有更多的课程,但每个课程都很少,而且只有一个职责。
顺便说一句,我们在一个中型项目中尝试了WCF RIA服务。而且进展不顺利。我们必须找到围绕框架的方法(hack)来完成我们想要的事情。而且它还基于代码生成-这对于构建服务器来说是非常糟糕的。另外,您永远都不应通过图层来查看。您应该能够在不影响客户端层的情况下更改支持的实体。使用RIA很难。我认为OData与WCF RIA属于同一类别。
如果您需要在客户端上构建查询,则可以使用规范模式-不要使用iqueryable-那么您将独立于后端实体。
祝好运。
推特:@lroal
关于.net - CRUD样式的数据驱动的分布式.NET应用程序体系结构问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3823016/
关闭。这个问题是opinion-based 。目前不接受答案。 想要改进这个问题吗?更新问题,以便 editing this post 可以用事实和引文来回答它。 . 已关闭 9 年前。 Improv
我刚刚发现了这门语言,我想知道是否可以使用数据库制作基本的 CRUD 网络应用程序。 最佳答案 有 mysql 的库和 postgresql , 核心库提供了一个 web server支持 HTTP、
Symfony 4.0 发布后,不再支持 SensioGeneratorBundle .因此命令 php app/console generate:doctrine:crud不可用。 他们建议使用 M
在开发 Web 应用程序时,我通常会看到人们执行增删改查和同步 View 的两种方式。 这里是使用 ajax 的高级示例。 1-方法一 创建操作可能涉及 POST 请求,成功后只需执行另一个 GET
我已经成功地使用 Yii2 模型和 CRUD 生成器为我的网络应用程序获取了一些框架代码文件。特别是,CRUD Generator 声称已成功将其 View 文件创建到: /basic/views//
在我的项目中,我一直在使用 Django 的通用 CRUD View 来处理很多事情。我现在想开始迁移到 DJango 1.3 中基于类的新样式通用 CRUD View 。我没有发现这些文档有多大帮助
关闭。这个问题需要details or clarity .它目前不接受答案。 想改进这个问题?通过 editing this post 添加详细信息并澄清问题. 7年前关闭。 Improve this
我希望标题不要太含糊,所以这里是: 我创建了一个 MySQL 数据库,其中存储了两个表:一个包含输入数据,另一个包含输出数据。 之后我编写了一个程序,连接到这个特定的数据库,从输入表中提取数据,解析它
我需要编辑我的实体以获得更多值。我已经用我之前的值生成了 crud。如何在编辑实体后通过应用程序/控制台重新生成 crud,以便它自动为其他值生成函数。 最佳答案 为此,您需要删除为此 crud 生成
因此,我仅使用 JavaScript 创建了一个简单的 CRUD 应用程序。现在,您可以将国家/地区添加到数组中并从数组中删除国家/地区。我希望能够编辑数组中的现有国家/地区,例如我想将“斯德哥尔摩”
我想让java中的一个类有一个可以与Hibernate配置交互并执行某些操作的方法,该方法被标识为ENUM(例如:读取,更新,添加,删除等) 方法参数应为(枚举操作、类 DTO、NamedQuery
我正在构建一个 React 应用程序,并使用 auth0 来登录/验证用户。 在使用 auth0 之前,我一直在对 API 进行 CRUD 调用来发布帖子。这又是在使用 auth0 之前、在我拥有用户
尝试使用 BlueJ 构建我的第一个 Java MySQL CRUD 应用程序。我可以运行该应用程序并将数据写入 MySQL 数据库。但是,当我运行搜索函数时,我得到了 Java .NullPoint
我正在试用 Microsoft Master Data Services,我想以编程方式将数据添加到数据库中。我开始获得模型/实体/成员结构,但我还不确定。如果您对此结构有很好的解释,请分享。 假设有
我正在尝试开发一个 Backbone Marionette 应用程序,我需要知道如何以最佳方式执行 CRUD(创建、读取、更新和销毁)操作。我找不到任何解释这一点的资源(仅适用于 Backbone)。
我已经根据文档和 medium article 模拟了与 Room 的多对多关系。 .使用这个@Relation,我可以从数据库中检索RecipeWithIngredients 或Ingredient
Closed. This question is opinion-based。它当前不接受答案。 想要改善这个问题吗?更新问题,以便editing this post用事实和引用来回答。 3年前关闭。
通过AngularJS通过REST进行CRUD操作的最佳实践是什么? 特别是这里的 Angular-Way 。我的意思是使用最少代码和最默认 Angular 设置来达到此目的的方式。 我知道$ res
我无法弄清楚我的更新功能。我能够从数据库中检索和删除,但我不知道如何更新。这对我来说是全新的,所以我很困惑。 .js 文件 //update user $("#btnUpdateUser").clic
我正在寻找一种对用户透明的 CRUD 操作后重新加载页面的方法。 实际上,在创建或删除之后,我必须重新加载页面才能显示我的操作。 我使用 api 来实现这个,当我将它与 json 文件一起使用时,它工
我是一名优秀的程序员,十分优秀!