将旧数据层替换为实体框架和 POCO 类的策略
本文关键字:POCO 策略 框架 实体 数据 替换 | 更新日期: 2023-09-27 17:57:08
我们正在处理的这个项目中使用.net C# 4.0,VS 2010,EF 4.1和遗留代码。
我正在处理一个 win 表单项目,我决定开始使用实体框架 4.1 来访问 ms sql db。代码库很旧,我们有一个使用数据适配器的现有数据层。这些数据适配器无处不在(在 Web 应用程序和 win 表单应用程序中)我的计划是随着时间的推移用 EF 替换旧的数据库访问代码,并摆脱 UI 层和数据层之间的紧密耦合。
因此,我的想法是或多或少地将 EF 与旧数据访问层相结合,并使用 EF 慢慢地将旧数据层替换为更现代的事物。因此,现在我们需要同时使用 EF 和旧版数据库访问代码。
到目前为止,我所做的是添加一个包含 edmx 文件和上下文的项目。EDMX 是使用数据库优先方法生成的。我还添加了另一个包含 POCO 类的项目(通过使用 POCO 实体生成器 ADO.NET)。我或多或少地遵循了Julia Lerman在她的书"编程实体框架"中关于如何拆分模型和生成的POCO类的方法。数据库模型已经设置了多年,更改表和关系、触发器、存储过程等不是一个选项,所以我基本上坚持使用数据库模型。
我已经阅读了有关存储库模式和工作单元的信息,我有点喜欢这些模式,但是当我同时要处理EF和旧数据库访问代码时,我很难实现它们。特别是当我没有时间将所有旧数据库访问代码替换为纯 EF 实现时。在一个完美的世界中,我会从一个新的数据模型重新开始,但这不是一个选择。
存储库和工作单元模式是这里要走的路吗?为了在我的业务层中使用 POCO 类,我有时需要使用 EF 和旧数据库代码来填充我的 POCO 类。换句话说,我有时可以使用 EF 检索我需要的部分数据,并使用旧的数据库访问层检索其余数据,然后将数据映射到我的 POCO 类。当我想更新一些数据时,我需要从 POCO 类中选取数据,并使用旧数据访问代码将数据存储在数据库中。因此,当我想在 UI 中显示数据时,我需要将从旧数据访问层检索的数据映射到我的 POCO 类,反之亦然,当我想将数据保存到数据库时。
为了使事情复杂化,我们将一些数据存储在运行时之前我们不知道名称的表中(请不要问我为什么:-))。因此,在旧的数据库访问层中,我们必须动态创建 sql 语句,其中我们根据来自其他表的信息插入表和列名称。
我还发现 POCO 类之间的关系有点过于以数据库为中心。换句话说,我觉得我需要有一个更简化的领域模型来使用。也许我应该创建一个符合要求的领域模型,然后将 POCO 类用作"DAO"来填充域模型类?
您将如何使用存储库模式和工作单元模式实现这一点?(如果这是要走的路)
警钟为我敲响!不久前,我们尝试做类似的事情(仅使用nHibernate而不是EF4)。我们在运行 ORM 时遇到了几个问题 ADO.NET - 数据库并发性是一个很大的问题。
数据库模型已设置为 年,这不是一个选择 更改表和 关系, 触发器, 存储 程序等,所以我基本上是 坚持使用数据库模型。
是的。同样的事情!问题是我们存储的过程包含很多业务逻辑,并且不是简单的 CRUD 过程,因此使用存储过程执行的各种更新来更新 ORM 一点也不容易 - 单一责任原则 - 不是一个好打破!
我的计划是更换旧的数据库 随着时间的推移,使用 EF 访问代码并获取 用于紧密耦合
的RID 在 UI 层和数据层之间。
也许您可以在不需要ORM的情况下解耦 - 如何将服务/外观层放在UI层的前面,以协调与底层域的所有交互并将其隐藏在UI中。
如果你的数据库是"王者",并且你的应用程序是高度数据驱动的,我认为你将永远在实现你提到的模式进行一场艰苦的战斗。
接受此项目的 ado.net - 在下一个绿地项目上使用 EF4 和 DDD 模式:)
EDMX + POCO 类生成器生成的是 EFv4 代码,而不是 EFv4.1 代码,但您不必为这些细节而烦恼。EFv4.1 只提供不同的 API,其功能完全相同(它只是 EFv4 API 的包装器)。
根据您使用数据集的方式,您可能会遇到一些非常困难的问题。数据集是更改集模式的表示形式。他们知道对数据进行了哪些更改,并且能够存储这些更改。EF 实体只有在附加到从数据库加载它们的上下文时才知道这一点。使用分离的实体后,必须付出很大的努力来告诉 EF 发生了哪些更改 - 尤其是在修改关系时(分离实体是 Web 应用程序和 Web 服务中的常见方案)。出于这些目的,EF 提供了另一个称为自跟踪实体的模板,但它们还有其他问题和限制(例如缺少延迟加载,当具有相同键的实体附加到上下文时无法应用更改等)。
EF 也不支持数据集中使用的多个功能 - 例如唯一键和批量更新。有趣的是,较新的 MS API 通常会解决以前 API 的一些难题,但同时提供的功能比以前的 API 少得多,这带来了新的麻烦。
另一个问题可能是性能 - EF 比使用数据集直接访问数据慢,并且内存消耗更高(是的,报告了一些内存泄漏)。
可以忘记使用 EF 访问在设计时不知道的表。EF 不允许任何动态行为。表名和数据库服务器的类型在映射中是固定的。另一个问题可能是使用触发器的方式 - ORM 工具不喜欢触发器,EF 在处理数据库计算值时功能有限(在数据库或应用程序中填充值的可能性是分离的)。
从 EF + 数据集填充 POCO 的方法听起来像是仅使用 EF 时无法实现的。EF 具有一些允许的映射模式,但将多个表映射到单个 POCO 类的可能性非常有限和受限(如果要使这些表可编辑)。如果您的意思是仅从 EF 加载一个实体,从数据适配器加载另一个实体,并且只是在它们之间进行引用,您应该没问题 - 在这种情况下,存储库听起来像是合理的模式,因为存储库的目的正是:加载或保留数据。工作单元也可以使用,因为您很可能希望在 EF 和数据适配器之间重用单个数据库连接,以避免在保存更改期间进行分布式事务处理。UoW将是负责处理此连接的地方。
EF 映射与数据库设计相关 - 可以引入一些面向对象的修改,但 EF 仍然紧密依赖于数据库。如果要使用某些高级域模型,则可能需要从 EF 和数据集填充单独的域类。同样,存储库将负责隐藏这些详细信息。
从我们实施的数量中,我学到了以下东西。
- POCO 和自跟踪对象很难处理,因为如果您对内部内容不容易理解,就会有许多意外行为,这些行为在您以前的项目中可能效果很好。
- 改变模式并不容易,到目前为止,我们一直在管理简单的CRUD而没有工作单元和身份映射模式。现在,我们过去编写的许多遗留代码都没有考虑这些新模式,并且逻辑将无法正常工作。
- 在我们之前的代码中,我们只是使用事务和直接发送到数据库的单个插入/更新/删除语句,假设服务器端的事务将处理所有操作。
- 在这种情况下,我们一直直接处理 ID,新生成的 ID 在单个插入语句后立即可用,但 EF 并非如此。
- 在 EF 中,我们不处理 ID,而是处理导航属性,这与早期的 ADO.NET 编程方法相比发生了巨大变化。
- 根据我们的经验,我们发现仅将 EF 替换为早期的数据访问代码会导致混乱。但是 EF + RIA 服务为您提供了一个全新的解决方案,您可能会获得所需的一切,并且您的 UI 将非常轻松地绑定到它。因此,如果您正在考虑使用 UI + RIA Services + EF 完全重写,那么这是值得的,因为查询管理中的大量依赖性会自动减少。你将只关注业务逻辑,但这是一个重大决定,完全重写或仅替换 EF 所需的工时几乎相同。
- 所以我们采用了UI + RIA服务+ EF的方式,我们开始替换一个模块。大多数情况下,EF 可以轻松地与现有基础结构共存,因此不会造成任何伤害。