我刚刚读完Scott的优秀著作“领域建模使功能:用域驱动的设计和F#解决软件复杂性”,其中他使用F# SQL类型提供程序进行数据库访问。
由于预见到了显而易见的问题,他说(p260)不要使用ORM,因为这样无法确保域的完整性。例如,ORM无法验证电子邮件地址,等等,无法处理嵌套的选择类型,等等。
然而,在这本书的前面(无法随手找到它,所以我希望我正确地引用他的话),在解释如何为工作流的每个部分创建边界时,他说数据应该在每个区段边界上被验证,允许该部分中的代码假设它都是有效的。
如果是这样的话,为什么不将来自ORM并进入您的代码中的实体视为跨越边界,并在那里验证它们?这样,您就可以获得ORM的好处,但可以确保您的模型的完整性。
发布于 2018-05-22 17:23:12
为了明确起见,我说“在F#中,我们倾向于不使用对象-关系映射器( ORM )”,但不是因为任何验证问题,而是因为像实体框架这样的大型ORM是高度面向对象的(惊讶!)它并不总是与功能范式很好地结合在一起。相反,F#ers要么使用类型提供程序,要么使用更简单的库(如Dapper )。
在“使用关系数据库”一章中,我确实说过,您可以以两种不同的方式处理数据库:
应用哪种情况取决于数据库是否与其他应用程序共享,如何设计数据库等等。
最新情况:我认识到以下句子可能会被误解:
难道我们不能只使用像实体框架或NHibernate这样的东西来自动完成所有这些映射吗?如果您想要确保域的完整性,则答案是否定的。
我的意思是,通过ORM将域模型直接转换到数据库意味着,您将失去域类型的复杂性--“使非法状态无法表示”的设计方法,这是我专门讨论的一章。这是因为ORMs不知道如何处理带有约束、复杂选择类型等的单用例联合。
相反,我建议您将域对象转换为专门为持久性设计的类型( " DTO "),然后使用该DTO进行持久化,而不是使用域类型。要存储/加载DTO,您当然可以使用EF或NHibernate,但是当您以这种方式使用它时,您不会从中获得太多的价值,因此通常使用类型提供程序或像Dapper这样的轻量级映射程序比较容易。
发布于 2018-05-22 15:40:40
如果你读了这本书的下一段,它会说:
使用类型提供程序而不是典型的运行时库的特殊之处在于,SQL类型提供程序将在编译时创建与SQL查询或SQL命令匹配的类型。如果SQL查询不正确,您将得到编译时错误,而不是运行时错误。如果SQL是正确的,它将生成一个与SQL代码的输出完全匹配的F#记录类型。
因此,这种方法似乎提供了一些与C#中的静态类型相同的保证。也就是说,如果您的类型不对齐,您将在编译时得到一个错误。
https://softwareengineering.stackexchange.com/questions/371344
复制相似问题