热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

EntityFramework之领域驱动设计实践【从DataTable到EntityObject】

从DataTable到EntityObject虽然从技术角度讲,DataTable与EntityObject并没有什么可比性,然而,它暗示了一场革命正在悄然进行着,即使是微软,

从DataTable到EntityObject

虽然从技术角度讲,DataTable与EntityObject并没有什么可比性,然而,它暗示了一场革命正在悄然进行着,即使是微软,也摆脱不了这场革命的飓风。

软件设计思想需要革命,需要摆脱原有的思路,而走向面向领域的道路。你或许会觉得听起来很玄乎,然而目前软件开发的现状使你不得不接受这样的现实,仍然有大帮的从业人员成天扯着数据库不放,仍然有大帮的人在问:“我要实现xxxx功能,我的数据库应该如何设计?”这些人犯了根本性的错误,就是把软件的目的搞错了,软件研究的是什么?是研究如何使用计算机来解决实际(领域)问题,而不是去研究数据应该如何保存更合理。这方面的事情我在我以前的博文中已经说过很多次了,在此就不再重复了。

当然,很多读者会跟我有着相同的观点,也会觉得我很“火星”,但这都不要紧,上面我所说的都是一个引子,希望能够帮助更多“步入歧途”的从业人员 “走上正路”。不错,软件设计应该从“数据库驱动”走向“领域驱动”,而领域驱动设计的实践经验正是为设计和开发大型复杂的软件系统提供了实践指导。

回到我们的副标题,从DataTable到EntityObject,你看到了什么?看到的是微软在领域驱动上的进步,从DataTable这一纯粹的数据组织形式,到EntityObject这一实体对象,微软带给我们的不仅仅是技术框架,更是一套面向领域的解决方案。

.NET 4.0来了,随之而来的是实体框架(EntityFramework,简称“EF”),在本系列文章中,我将结合领域驱动设计的实践知识,来剖析EF的具体应用过程,当然,现在的EF还并不是那么完善,我也非常期待能够看到,今后微软能够继续发展和完善EF,使其成为微软领域驱动工具箱中的重要角色。

先不说EF,首先我们简要地分析一下,作为一种框架,要支持领域驱动的思想,需要满足哪些硬性需求,之后再仔细想想,.NET EF是否真的能够很好地应用在领域驱动上。



  • 首先需要能够正确对待“领域模型”的概念。领域模型与数据模型不同,它表述的是领域中各个类及其之间的关系。类关系是多样的,比如组合、聚合、继承、实现、约束等,而数据模型不是一对多,就是多对多。从领域驱动设计的角度看,数据库只不过是存储实体的一个外部机制,是属于技术层面的东西。数据模型主要用于描述领域模型对象的持久化方式,应该是先有领域模型,才有数据模型,领域模型需要通过某种映射而产生相应的数据模型。因此,框架必须支持从领域模型到数据模型的映射。

    EF不仅支持从领域模型生成数据库的DDL,而且支持从数据库结构来生成“领域模型”。我倒是觉得后者可以去掉,因为从数据库得到的已经不是领域模型了。你会问为什么,我可以告诉你,单纯的数据是没办法描述领域概念的。比如:你的数据库里有一个表叫做“Customer”,在通过数据库结构生成“领域模型”的时候,Visual Studio当然会帮你生成一个“领域对象”叫做Customer,但如果我把这数据表的名字改为“abc”,虽然里面还是存的客户信息,但EF并不知道这一点,也是照样生成一个“abc”的类,而这样的东西能算是领域对象吗?因此,数据依赖于实体,是实体的状态,离开实体的数据毫无意义

    bubuko.com,布布扣 

    上图中标记的内容,根据领域驱动设计的思想,是不应该保存的。然而.NET是一个产品,它需要顾及到各种需求,因此,“从数据库生成模型”的功能也将被保留下来

  • 对“聚合”概念的支持。聚合是一系列表述同一概念的相互关联的实体的集合,比如销售订单、销售订单行以及商品,这三个实体可以整合成一个聚合,销售订单则是聚合的根。关于聚合的问题将在后续文章中讨论。为什么引入聚合?这是领域驱动设计处理大型软件系统的一种独到的方式。软件系统的实体对象可能非常多,之间的关系也可能错综复杂,那么,当我们需要从外部持久化机制“唤醒”(或者说读取)某个实体对象的时候,是不是需要将它以及它所关联的所有对象都一并读入内存呢?当然不是,因为我们只需要关注整个问题的某个方面。比如在读取客户数据的时候,我们或许会将这个客户的所有订单显示出来,但不会将每个订单的订单行也全部读出来,因为现在我们还没有决定是否真的需要查看所有的订单行。

    EF目前不支持聚合概念,所有的实体都被一股脑地塞进ObjectContext对象的EntitySet属性当中,不过这没关系,接下来的文章我会介绍如何在EF中引入聚合的概念

  • 值对象支持。了解领域驱动设计的朋友都知道,领域模型对象分为实体、值对象和服务。以前的LINQ to SQL不支持值对象,很郁闷,现在好了,EF支持值对象,其表现为ComplexType类型。在这里我想提两点,首先,EF还不支持枚举类型,不要小看枚举类型,与整型类型相比,它能够更好地表达领域语义,比如销售订单的状态可以有 Created,Picked,Packed,Shipped,Delivered,Invoiced,Returned和Cancelled,如果用 0,1,2,3,4,5,6,7来表示,你就会看不懂了,因为这些整数都不是“自描述”的,你需要去读额外的文档来了解它们的意思。其次就是我不太喜欢将
    ComplexType定义为引用类型,我觉得用值类型就会更加轻量。当然,我不反对使用引用类型,毕竟EF也是出于框架设计的需要

  • 实体不仅有状态,还应该有行为。这是很自然的事情,我们应该使用“富领域模型”,而不仅仅是搞一些 POCO加一些getter/setter方法。因为对象本身就应该有行为,这才能够以自然的方式描述现实领域。很可惜,EF的Entity Data Model Designer只支持对象状态(属性)的图形化定义,而不支持行为定义,这也给EF带来了一个硬伤:没法定义行为的重载和重写,而这些却恰恰是业务逻辑的重要组成部分。我更希望在下一代EF中,能够看到的是“Entity Model Designer”,而不是“Entity
    Data Model Designer”。当然,我们也可以通过使用C#中部分类(partial class)的特性,向实体注入行为,这并不影响实体对领域概念的描述性。

    最糟糕的就算是,EF居然支持从数据库的存储过程来生成实体对象的方法。这从根本上把技术问题和领域问题混为一谈,我认为这个功能也可以去掉,因为存储过程面向的是数据,而实体方法面向的是领域。有关存储过程的问题,我在后面的文章中也会提到

    bubuko.com,布布扣

从上面的描述,我们对EF的功能有了个大概的了解,接下来的系列文章,我会和大家一起,一步步地探讨,如何在EF上应用领域驱动设计的思想,进而完成我们的案例程序。本系列文章均为我个人原创,或许在某些问题上你会有不同意见,不要紧,你可以直接签写留言,或者发邮件给我,期待与你的探讨,期待与你在软件架构设计的道路上共同进步。


推荐阅读
  • Unity3D 中 AsyncOperation 实现异步场景加载及进度显示优化技巧
    在Unity3D中,通过使用`AsyncOperation`可以实现高效的异步场景加载,并结合进度条显示来提升用户体验。本文详细介绍了如何利用`AsyncOperation`进行异步加载,并提供了优化技巧,包括进度条的动态更新和加载过程中的性能优化方法。此外,还探讨了如何处理加载过程中可能出现的异常情况,确保加载过程的稳定性和可靠性。 ... [详细]
  • 本指南介绍了如何在ASP.NET Web应用程序中利用C#和JavaScript实现基于指纹识别的登录系统。通过集成指纹识别技术,用户无需输入传统的登录ID即可完成身份验证,从而提升用户体验和安全性。我们将详细探讨如何配置和部署这一功能,确保系统的稳定性和可靠性。 ... [详细]
  • Python 伦理黑客技术:深入探讨后门攻击(第三部分)
    在《Python 伦理黑客技术:深入探讨后门攻击(第三部分)》中,作者详细分析了后门攻击中的Socket问题。由于TCP协议基于流,难以确定消息批次的结束点,这给后门攻击的实现带来了挑战。为了解决这一问题,文章提出了一系列有效的技术方案,包括使用特定的分隔符和长度前缀,以确保数据包的准确传输和解析。这些方法不仅提高了攻击的隐蔽性和可靠性,还为安全研究人员提供了宝贵的参考。 ... [详细]
  • C# .NET 4.1 版本大型信息化系统集成平台中的主从表事务处理标准示例
    在C# .NET 4.1版本的大型信息化系统集成平台中,本文详细介绍了主从表事务处理的标准示例。通过确保所有操作要么全部成功,要么全部失败,实现主表和关联子表的同步插入。主表插入时会返回当前生成的主键,该主键随后用于子表插入时的关联。以下是一个示例代码片段,展示了如何在一个数据库事务中同时添加角色和相关用户。 ... [详细]
  • 在Eclipse中提升开发效率,推荐使用Google V8插件以增强Node.js的调试体验。安装方法有两种:一是通过Eclipse Marketplace搜索并安装;二是通过“Help”菜单中的“Install New Software”,在名称栏输入“googleV8”。此插件能够显著改善调试过程中的性能和响应速度,提高开发者的生产力。 ... [详细]
  • 在 Axublog 1.1.0 版本的 `c_login.php` 文件中发现了一个严重的 SQL 注入漏洞。该漏洞允许攻击者通过操纵登录请求中的参数,注入恶意 SQL 代码,从而可能获取敏感信息或对数据库进行未授权操作。建议用户尽快更新到最新版本并采取相应的安全措施以防止潜在的风险。 ... [详细]
  • Web开发框架概览:Java与JavaScript技术及框架综述
    Web开发涉及服务器端和客户端的协同工作。在服务器端,Java是一种优秀的编程语言,适用于构建各种功能模块,如通过Servlet实现特定服务。客户端则主要依赖HTML进行内容展示,同时借助JavaScript增强交互性和动态效果。此外,现代Web开发还广泛使用各种框架和库,如Spring Boot、React和Vue.js,以提高开发效率和应用性能。 ... [详细]
  • 本文探讨了在任务完成后将其转换为最终状态时的异常处理机制。通过分析 `TaskCompletionSource` 的使用场景,详细阐述了其在异步编程中的重要作用,并提供了具体的实现方法和注意事项,帮助开发者更好地理解和应用这一技术。 ... [详细]
  • 该问题可能由守护进程配置不当引起,例如未识别的JVM选项或内存分配不足。建议检查并调整JVM参数,确保为对象堆预留足够的内存空间(至少1572864KB)。此外,还可以优化应用程序的内存使用,减少不必要的内存消耗。 ... [详细]
  • 如何在C#中配置组合框的背景颜色? ... [详细]
  • 本文探讨了如何在C#应用程序中通过选择ComboBox项从MySQL数据库中检索数据值。具体介绍了在事件处理方法 `comboBox2_SelectedIndexChanged` 中可能出现的常见错误,并提供了详细的解决方案和优化建议,以确保数据能够正确且高效地从数据库中读取并显示在界面上。此外,还讨论了连接字符串的配置、SQL查询语句的编写以及异常处理的最佳实践,帮助开发者避免常见的陷阱并提高代码的健壮性。 ... [详细]
  • ButterKnife 是一款用于 Android 开发的注解库,主要用于简化视图和事件绑定。本文详细介绍了 ButterKnife 的基础用法,包括如何通过注解实现字段和方法的绑定,以及在实际项目中的应用示例。此外,文章还提到了截至 2016 年 4 月 29 日,ButterKnife 的最新版本为 8.0.1,为开发者提供了最新的功能和性能优化。 ... [详细]
  • Spring框架的核心组件与架构解析 ... [详细]
  • C#编程中按钮控件的使用与优化 ... [详细]
  • Parallels Desktop for Mac 是一款功能强大的虚拟化软件,能够在不重启的情况下实现在同一台电脑上无缝切换和使用 Windows 和 macOS 系统中的各种应用程序。该软件不仅提供了高效稳定的性能,还支持多种高级功能,如拖放文件、共享剪贴板等,极大地提升了用户的生产力和使用体验。 ... [详细]
author-avatar
微笑
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有