Having tried both data-aware and non data-aware style of Delphi applications I'm back in the data-aware component camp these days. It takes a bit of work and discipline to correctly layer the code but it's still quicker than doing everything by hand using non data-aware controls.
A few of my tips for data-aware component usage are
Don't just rewrite FishFact on a larger scale. Put some thought into your design.
Don't use a TDataModule, use many TDataModules each responsible for just a small aspect of your applications data.
TDatasets belong on TDataModules, while TDataSources belong on TForms (unless used for master/detail relationships).
Use in-memory datasets such as the DataSnap TClientDataSet.
Your ClientDataSets don't have to mirror your database tables exactly. DataSnap allows you massage your data structures in memory so you can produce datasets tailored for specific purposes. Specifically you can do things like
Joining two or more tables into the one editable dataset
Denormalizing master detail table structures, can simplify your UI code sometimes.
Create in-memory only fields (like calculated fields but you can write to them also)
TClientDataSet nested tables are useful but not the only way to express master detail relationships. Sometimes it's better to do it the old way with two independent TClientDataSets joined through a TDataSource.
Data aware controls are great, but you have to make sure you get your business code in a separate layer.
That is not difficult, but you need to be aware on how you can do that.
One approach is to have your DataSet components in a DataModule (or other non visual container).
Another handy trick is to use a TClientDataSet to do the UI entry, and use that as an intermediate buffer between the UI and the business layer. The business layer then uses TDataSet components specific to your data layer.
Delphi data-aware components are not depended on the back-end database engine you are using, so using Firebird or MS SQL Server or Oracle or others doesn't matter to your data-aware components. They only know the datasource component assigned to them and do all their DB related stuff via that.
For me, if something can be done with data-aware components in a nice way, I will use them. These are usually small projects which should be done in a short-time. In bigger projects, I might totally rule out data-aware components or use them in forms that are merely used for data presentation and do not receive user input. When it comes to receiving user input, I might use non-data-aware components because I have more flexibility in controlling them and validate the input. Of course data-ware components can be still useful in such scenarios too. You still can validate user input in dataset events like OnBeforePost. Also if you are using a multi-tier design, and your client app represents data presenter layer, your input validation is done in the middle-tier so you can receive input using data-aware components in the client app, and send them to the middle-tier for validation and further processing.
从 RAD 和原型设计的角度来看,数据感知组件非常有用,尤其是当您设计基于数据的报告或网格时。即您可以在设计时进行修补。 所以我就这样使用它们。但当需要将其转换为交付代码时,我几乎总是切断连接,从查询中删除 SQL,并在代码中完成所有操作。这样更容易预测和维护,特别是在具有版本控制的多开发人员环境中。当 SQL 嵌入到表单中的某个位置时,试图找出 SQL 实际所在的位置是一件非常痛苦的事情。尤其糟糕的是,在两个地方都有 SQL,然后必须弄清楚哪个地方有效。
Data-aware components are usful from a RAD and prototyping perspective, especially when you're designing reports or grids that are based on data. i.e. you can tinker at design time. So I use them like that. But when it comes time to transform it into shipping code, I almost always sever the connections, remove the SQL from the queries, and do everything in code. It's much more predictable and maintainable that way, especially in a multi-developer environment with version control. When the SQL is embedded in the form somewhere, it's a big pain to try to figure out where the SQL actually resides. And it's especially bad to have SQL in two places, and then have to figure out which is in effect.
发布评论
评论(7)
我发现使用数据感知组件会导致应用程序的业务逻辑和 UI 逻辑之间没有明显的区别。
这对于小型项目来说很好,但随着项目变得越来越大,代码变得越来越难以维护。
事件代码的所有各个部分(及其交互)都可能成为理解的真正噩梦!
在这种情况下,我总是放弃数据感知组件并转而使用(手工编码的)MVC 设计。
这确实需要大量的前期编码工作,但结果(恕我直言)是一个可维护、可扩展和可调试的项目。
I've found that using the data-aware components results in an application with no clear distinction between business and UI logic.
This is fine for small projects but as they grow larger the code becomes less and less maintainable.
All the various bits of event code (and their interactions) can become a real nightmare to understand!
Invariably in such cases I've ditched data-aware components and have switched to a (hand-coded) MVC design.
This does require a lot of up-front coding effort but results (IMHO) in a project that is maintainable, extensible and debuggable.
在尝试了数据感知和非数据感知风格的 Delphi 应用程序之后,这些天我又回到了数据感知组件阵营。正确地对代码进行分层需要一些工作和纪律,但它仍然比使用非数据感知控件手动完成所有操作要快。
我关于数据感知组件使用的一些技巧是:
不要只是大规模地重写 FishFact。对您的设计进行一些思考。
不要使用 TDataModule,使用许多 TDataModule,每个 TDataModule 只负责应用程序数据的一小部分。
TDatasets 属于 TDataModules,而 TDataSources 属于 TForms(除非用于主/从关系)。
使用内存数据集,例如 DataSnap TClientDataSet。
您的 ClientDataSet 不必完全镜像您的数据库表。 DataSnap 允许您管理内存中的数据结构,以便您可以生成为特定目的量身定制的数据集。具体来说,你可以做类似的事情
将两个或多个表连接到一个可编辑数据集中
非规范化主从表结构,有时可以简化您的 UI 代码。
仅创建内存中的字段(例如计算字段,但您也可以写入它们)
TClientDataSet 嵌套表是有用但不是表达主细节关系的唯一方法。有时,最好采用旧方法,通过 TDataSource 连接两个独立的 TClientDataSet。
Having tried both data-aware and non data-aware style of Delphi applications I'm back in the data-aware component camp these days. It takes a bit of work and discipline to correctly layer the code but it's still quicker than doing everything by hand using non data-aware controls.
A few of my tips for data-aware component usage are
Don't just rewrite FishFact on a larger scale. Put some thought into your design.
Don't use a TDataModule, use many TDataModules each responsible for just a small aspect of your applications data.
TDatasets belong on TDataModules, while TDataSources belong on TForms (unless used for master/detail relationships).
Use in-memory datasets such as the DataSnap TClientDataSet.
Your ClientDataSets don't have to mirror your database tables exactly. DataSnap allows you massage your data structures in memory so you can produce datasets tailored for specific purposes. Specifically you can do things like
Joining two or more tables into the one editable dataset
Denormalizing master detail table structures, can simplify your UI code sometimes.
Create in-memory only fields (like calculated fields but you can write to them also)
TClientDataSet nested tables are useful but not the only way to express master detail relationships. Sometimes it's better to do it the old way with two independent TClientDataSets joined through a TDataSource.
查看 ORM 解决方案。
这是一种采用多层架构的好方法。请参阅DELPHI win32 的 ORM
Take a look at ORM solutions.
It's a nice approach with multi-tier architecture. See ORM for DELPHI win32
数据感知控件很棒,但您必须确保将业务代码放在单独的层中。
这并不困难,但您需要了解如何做到这一点。
一种方法是将 DataSet 组件放在 DataModule(或其他非可视容器)中。
另一个方便的技巧是使用 TClientDataSet 来执行 UI 条目,并将其用作 UI 和业务层之间的中间缓冲区。然后,业务层使用特定于数据层的 TDataSet 组件。
——杰罗恩
Data aware controls are great, but you have to make sure you get your business code in a separate layer.
That is not difficult, but you need to be aware on how you can do that.
One approach is to have your DataSet components in a DataModule (or other non visual container).
Another handy trick is to use a TClientDataSet to do the UI entry, and use that as an intermediate buffer between the UI and the business layer. The business layer then uses TDataSet components specific to your data layer.
--jeroen
Delphi 数据感知组件不依赖于您正在使用的后端数据库引擎,因此使用 Firebird 或 MS SQL Server 或 Oracle 或其他引擎对于您的数据感知组件并不重要。他们只知道分配给他们的数据源组件,并通过它来完成所有与数据库相关的事情。
对我来说,如果可以用数据感知组件以一种很好的方式完成某些事情,我就会使用它们。这些通常是小项目,应该在短时间内完成。在更大的项目中,我可能完全排除数据感知组件,或者以仅用于数据呈现而不接收用户输入的形式使用它们。在接收用户输入时,我可能会使用非数据感知组件,因为我可以更灵活地控制它们并验证输入。当然,数据件组件在这种情况下也仍然有用。您仍然可以在 OnBeforePost 等数据集事件中验证用户输入。此外,如果您使用多层设计,并且您的客户端应用程序代表数据呈现器层,则您的输入验证是在中间层完成的,因此您可以使用客户端应用程序中的数据感知组件接收输入,并将它们发送到用于验证和进一步处理的中间层。
Delphi data-aware components are not depended on the back-end database engine you are using, so using Firebird or MS SQL Server or Oracle or others doesn't matter to your data-aware components. They only know the datasource component assigned to them and do all their DB related stuff via that.
For me, if something can be done with data-aware components in a nice way, I will use them. These are usually small projects which should be done in a short-time. In bigger projects, I might totally rule out data-aware components or use them in forms that are merely used for data presentation and do not receive user input. When it comes to receiving user input, I might use non-data-aware components because I have more flexibility in controlling them and validate the input. Of course data-ware components can be still useful in such scenarios too. You still can validate user input in dataset events like OnBeforePost. Also if you are using a multi-tier design, and your client app represents data presenter layer, your input validation is done in the middle-tier so you can receive input using data-aware components in the client app, and send them to the middle-tier for validation and further processing.
从 RAD 和原型设计的角度来看,数据感知组件非常有用,尤其是当您设计基于数据的报告或网格时。即您可以在设计时进行修补。
所以我就这样使用它们。但当需要将其转换为交付代码时,我几乎总是切断连接,从查询中删除 SQL,并在代码中完成所有操作。这样更容易预测和维护,特别是在具有版本控制的多开发人员环境中。当 SQL 嵌入到表单中的某个位置时,试图找出 SQL 实际所在的位置是一件非常痛苦的事情。尤其糟糕的是,在两个地方都有 SQL,然后必须弄清楚哪个地方有效。
Data-aware components are usful from a RAD and prototyping perspective, especially when you're designing reports or grids that are based on data. i.e. you can tinker at design time.
So I use them like that. But when it comes time to transform it into shipping code, I almost always sever the connections, remove the SQL from the queries, and do everything in code. It's much more predictable and maintainable that way, especially in a multi-developer environment with version control. When the SQL is embedded in the form somewhere, it's a big pain to try to figure out where the SQL actually resides. And it's especially bad to have SQL in two places, and then have to figure out which is in effect.
您可以使用Unidac,它支持许多数据库服务器,包括Firebird(我使用的)并且具有非常好的功能。
与 Remobject SDK 结合使用,您将拥有 n 层架构和数据库抽象的完美组合。
You can use Unidac which supports many database servers, including Firebird (that i use) and has very nice features.
Coupled with Remobject SDK you will have a nice combination of n-tier architecture and database abstraction.