使用实体框架和 POCO 类替换旧数据层的策略
在我们正在进行的这个项目中,我们使用 .net C# 4.0、VS 2010、EF 4.1 和遗留代码。
我正在开发一个 win form 项目,我决定开始使用实体框架 4.1 来访问 ms sql 数据库。代码库相当旧,我们有一个使用数据适配器的现有数据层。这些数据适配器随处可见(在 Web 应用程序和 win 表单应用程序中)我的计划是随着时间的推移用 EF 替换旧的数据库访问代码,并摆脱 UI 层和数据层之间的紧密耦合。
因此,我的想法是或多或少地将 EF 与遗留数据访问层结合起来,并使用 EF 的更现代的方式慢慢取代遗留数据层。因此,现在我们需要同时使用 EF 和旧的数据库访问代码。
到目前为止我所做的是添加一个包含 edmx 文件和上下文的项目。 edmx 是使用数据库优先方法生成的。我还添加了另一个包含 POCO 类的项目(通过使用 ADO.NET POCO 实体生成器)。我或多或少遵循了 Julia Lerman 在她的《编程实体框架》一书中关于如何拆分模型和生成的 POCO 类的方法。数据库模型已经设置多年,并且无法更改表和关系、触发器、存储过程等,所以我基本上坚持使用数据库模型。
我已经阅读了有关存储库模式和工作单元的内容,并且我有点喜欢这些模式,但是当我同时要处理 EF 和遗留数据库访问代码时,我很难实现它们。特别是当我没有时间用纯 EF 实现替换所有旧版数据库访问代码时。在完美的世界中,我会重新开始一个新的数据模型,但这不是这里的选择。
存储库和工作单元模式是这里的方法吗?为了在我的业务层中使用 POCO 类,我有时需要使用 EF 和旧数据库代码来填充我的 POCO 类。换句话说,我有时可以使用 EF 检索我需要的部分数据,并使用旧的数据库访问层检索其余数据,然后将数据映射到我的 POCO 类。当我想要更新一些数据时,我需要从 POCO 类中选取数据并使用旧的数据访问代码将数据存储在数据库中。因此,当我想在 UI 中显示数据时,我需要将从旧数据访问层检索到的数据映射到 POCO 类,反之亦然,当我想将数据保存到数据库时。
为了使事情复杂化,我们将一些数据存储在我们在运行前不知道名称的表中(请不要问我为什么:-))。因此,在旧的数据库访问层中,我们必须动态创建 sql 语句,根据其他表的信息插入表名和列名。
我还发现 POCO 类之间的关系有点过于以数据库为中心。换句话说,我觉得我需要一个更简化的领域模型来使用。也许我应该创建一个符合要求的域模型,然后使用 POCO 类作为“DAO”来填充域模型类?
您将如何使用存储库模式和工作单元模式来实现这一点? (如果这是要走的路)
We are using .net C# 4.0, VS 2010, EF 4.1 and legacy code in this project we are working on.
I'm working on a win form project where I have made a decision to start using entity framework 4.1 for accessing an ms sql db. The code base is quite old and we have an existing data layer that uses data adapters. These data adapters are used all over the place (in web apps and win form apps) My plan is to replace the old db access code with EF over time and get rid for the tight coupling between UI layers and data layer.
So my idea is to more or less combine EF with the legacy data access layer and slowly replace the legacy data layer with a more modern take on things using EF. So for now we need to use both EF and the legacy db access code.
What I have done so far is to add a project containing the edmx file and context. The edmx is generated using database first approach. I have also added another project that contains the POCO classes (by using ADO.NET POCO Entity Generator). I have more or less followed Julia Lerman's approach in her book "Programming Entity Framework" on how to split the model and the generated POCO classes. The database model has been set for years and it's not an option the change the table and the relationships, triggers, stored procedures, etc, so I'm basically stuck with the db model as it is.
I have read about the repository pattern and unit of work and I kind of like the patterns, but I struggle to implement them when I have both EF and the legacy db access code to deal with. Specially when I don't have the time to replace all of the legacy db access code with a pure EF implementation. In an perfect world I would start all over again with a fresh take one the data model, but that is not an option here.
Is the repository and unit of work patterns the way to go here? In order to use the POCO classes in my business layer, I sometimes need to use both EF and the legacy db code to populate my POCO classes. In another words, I can sometimes use EF to retrieve a part of the data I need and the use the old db access layer to retrieve the rest of the data and then map the data to my POCO classes. When I want to update some data I need to pick data from the POCO classes and use the legacy data access code to store the data in the database. So I need to map the data retrieved from the legacy data access layer to my POCO classes when I want to display the data in the UI and vice versa when I want to save data to the data base.
To complicate things we store some data in tables that we don't know the name of before runtime (Please don't ask me why:-) ). So in the old db access layer, we had to create sql statements on the fly where we inserted the table and column names based on information from other tables.
I also find that the relationships between the POCO classes are somewhat too data base centric. In another words, I feel that I need to have a more simplified domain model to work with. Perhaps I should create a domain model that fits the bill and then use the POCO classes as "DAO's" to populate the domain model classes?
How would you implement this using the Repository pattern and Unit of Work pattern? (if that is the way to go)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
给我敲响了警钟!不久前我们尝试做类似的事情(仅使用 nHibernate,而不是 EF4)。我们在运行 ADO.NET 和 ORM 时遇到了几个问题 - 数据库并发性是一个大问题。
是的。同样的事情!问题是我们的存储过程包含大量业务逻辑,并且不是简单的 CRUD 过程,因此使用存储过程执行的各种更新来保持 ORM 更新根本不容易 - 单一职责原则 - 不是一个好打破的原则!
也许您可以在不需要 ORM 的情况下解耦 - 如何在 UI 层前面放置一个服务/外观层来协调与底层域的所有交互并将其从 UI 中隐藏。
如果您的数据库是“王”并且您的应用程序是高度数据驱动的,我认为您将始终在实现您提到的模式方面进行一场艰苦的战斗。
在此项目中采用 ado.net - 在您的下一个绿色项目中使用 EF4 和 DDD 模式:)
Alarm bells are ringing for me! We tried to do something similar a while ago (only with nHibernate not EF4). We had several problems running ADO.NET along side an ORM - database concurrency being a big one.
Yep. Same thing! The problem was that our stored procs contained a lot of business logic and weren't simple CRUD procs so keeping the ORM updated with the various updates performed by a stored procedure was not easy at all - Single Responsibility Principle - not a good one to break!
Maybe you could decouple without the need for an ORM - how about putting a service/facade layer infront of your UI layer to coordinate all interactions with the underlying domain and hide it from the UI.
If your database is 'king' and your app is highly data driven I think you will always be fighting an uphill battle implementing the patterns you mention.
Embrace ado.net for this project - use EF4 and DDD patterns on your next green field proj :)
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 和数据集填充单独的域类。同样,存储库有责任隐藏这些详细信息。
EDMX + POCO class generator results in EFv4 code, not EFv4.1 code but you don't have to bother with these details. EFv4.1 offers just different API which does exactly the same (and it is only wrapper around EFv4 API).
Depending on the way how you use datasets you can reach some very hard problems. Datasets are representation of the change set pattern. They know what changes were done to data and they are able to store just these changes. EF entities know this only if they are attached to the context which loaded them from the database. Once you work with detached entities you must make a big effort to tell EF what has changed - especially when modifying relations (detached entities are common scenario in web applications and web services). For those purposes EF offers another template called Self-tracking entities but they have another problems and limitations (for example missing lazy loading, you cannot apply changes when entity with the same key is attached to the context, etc.).
EF also doesn't support several features used in datasets - for example unique keys and batch updates. It's fun that newer MS APIs usually solve some pains of previous APIs but in the same time provide much less features then previous APIs which introduces new pains.
Another problem can be with performance - EF is slower then direct data access with datasets and have higher memory consumption (and yes there are some memory leaks reported).
You can forget about using EF for accessing tables which you don't know at design time. EF doesn't allow any dynamic behavior. Table names and the type of database server are fixed in mapping. Another problems can be with the way how you use triggers - ORM tools don't like triggers and EF has limited features when working with database computed values (possibility to fill value in the database or in the application is disjunctive).
The way of filling POCOs from EF + Datasets sounds like this will not be possible when using only EF. EF has some allowed mapping patterns but possibilities to map several tables to single POCO class are extremely limited and constrained (if you want to have these tables editable). If you mean just loading one entity from EF and another entity from data adapter and just make reference between them you should be OK - in this scenario repository sounds like reasonable pattern because the purpose of the repository is exactly this: load or persist data. Unit of work can be also usable because you will most probably want to reuse single database connection between EF and data adapters to avoid distributed transaction during saving changes. UoW will be the place responsible for handling this connection.
EF mapping is related to database design - you can introduce some object oriented modifications but still EF is closely dependent on the database. If you want to use some advanced domain model you will probably need separate domain classes filled from EF and datasets. Again it will be responsibility of repository to hide these details.
从我们实施的情况来看,我学到了以下几点。
From how much we have implemented, I have learned following things.