4

我正在处理一个数据库,其中包含不一致的数据,例如白色前导和尾随空格。

一般来说,我看到许多开发人员通过修剪几乎所有来自数据库的字符串来练习防御性编码,这些字符串可能在某个时候由用户输入。在我的oppinoin 中,最好在数据持久化之前进行这种格式化,这样它只完成一次,然后数据可以处于一致和可靠的状态。不幸的是,情况并非如此,但这导致我使用Trim方法找到下一个最佳解决方案。

如果我修剪所有数据作为我的数据访问层的一部分,那么我不必担心我的领域层的业务对象内的防御性修剪。如果我改为将修剪责任放在我的业务对象中,例如使用我的 C# 属性的 set 访问器,我应该得到相同的净结果,但是修剪将在分配给我的业务对象属性的所有值上运行,而不仅仅是那些来的来自不一致的数据库。

我想这是一个有点哲学的问题,它可能决定我可以问的答案“域层是否应该负责数据的防御/强制格式化? ” 让业务对象上的 PhoneNumber 属性的 set 访问器接受一个未格式化或格式化的字符串,然后尝试根据需要对其进行格式化,还是应该将此责任推给表示层和数据访问层,从而使域层对它将接受的数据类型更加严格?我认为这可能是更根本的问题。

更新:下面是一些我认为我应该分享的关于该主题的链接。

信息服务模式,第 3 部分:数据清理模式

LINQ to SQL - 在保存之前格式化字符串?

如何使用 Linq to Sql 修剪值?

4

3 回答 3

3

我建议“清理”应用程序层中的数据。您想在此处执行此操作的原因(是的,像 Dev Art 建议的那样在堆栈中更高)是因为您的域模型应该尽可能地“建模”域。如果在某个时间点所有数据都是“干净的”怎么办?好吧,那么您可能想要删除执行“清理”的辅助方法。更容易从应用程序堆栈中更高的位置删除它。

使用使用反射的经典扩展方法(不要从告诉我反射很慢,直到你知道它是如何工作的)或其他东西来挖掘域对象图的所有“字符串”属性(例如)。这是一个使用这种技术将DateTime调整为固定偏移量的示例 - 请注意它将如何“偏移”所有DateTime值,即使是在集合或其他自定义类型的深处。在您的情况下,抵消将是您的修剪。这肯定比.Trim()在整个节目中添加 s 更容易,并且可以相当容易地解耦。

请记住,不良数据是您的域的横切关注点,因此不应直接与它相关联(想想AOP)。

于 2010-05-11T17:38:39.803 回答
2

数据必须在持久化之前进行清理。现在它已被持久化,您有不干净的数据,可能需要在数据库中进行清理。考虑按姓名寻找客户。如果我存储的是“John”、“Doe”,我能找到“John”、“Doe”吗?

在靠近 UI 的地方清理数据可以让您拥有更简单的代码。防御代码可以从清理代码变为断言。(即断言字符串=修剪(字符串))。要达到这一点,您需要清理数据库以及 UI 代码。

于 2010-05-12T03:22:19.753 回答
0

最好在数据持久化之前进行这种格式化

绝对地。

域以后是否应该负责数据的防御/强制格式化?

使用当前存储的数据,您将找不到合适的位置来介绍修剪。这是因为你的存储的一致性被打破了。

你可以试试自我修复的方法。在对话中显示之前,读取数据并将其修剪到某处。一旦用户保存此对话,数据库中的数据就会“固定”。

至于新的输入,我倾向于认为修剪数据是一些既不属于域层也不属于数据层的清理操作。在您实际开始使用该数据之前,用户输入应该在靠近 UI 层的某个地方“清理”。

于 2010-05-11T11:22:54.287 回答