我正在使用 ASP.NET Webforms + EF4 启动一个新的 Web 项目。我正在尝试按照本教程应用具有工作单元模式的存储库模式: http://www.dotnetage.com/publishing/home/2011/07/05/6883/the-repository-pattern-with-ef-code-first-dependeny-injection-in-asp- net-mvc3.html
我想我明白了,但我的问题是,当我在模型中创建一个新对象时,我是否还必须在 Unit Of 的 IDALContext 中定义该对象 工作?这不是快速发展的断手吗?此外,如果您与多个开发人员合作,并且您不希望其他开发人员看到您的 DAL,您该如何管理呢?因为据我了解,在这种模式中,当您在模型中创建新对象时,您还必须在本教程的 IDALContext 中定义它。抱歉我对此感到很困惑。
I'm starting a new web project using ASP.NET Webforms + EF4. I'm trying to apply a repository pattern with a unit of work pattern following this tutorial : http://www.dotnetage.com/publishing/home/2011/07/05/6883/the-repository-pattern-with-ef-code-first-dependeny-injection-in-asp-net-mvc3.html
I think I got the idea but my question is that, when I create a new object in the model, do I also have to define that object in IDALContext of the Unit Of Work? Isn't that a handbreak for rapid development? Also if you work with multiple developers and if you don't want other developers to see your DAL, how can you manage this? Because in this pattern as I understand, when you create a new object in the model you also have to define it in the IDALContext for this tutorial. Sorry I'm so confused by this.
发布评论
评论(4)
您应该考虑“命令/查询对象”作为替代方案,您可以在该领域找到很多有趣的文章,但这里有一些不错的文章:
https://bigmachine.io/2014/03/04/repositories-and-unitofwork-are-not-a-good-idea/
https://www.dotnetcurry.com/patterns-practices/ 1461/command-query-separation-cqs
您将坚持每个命令使用一个命令对象来启用简单事务,从而避免对 Unit Of 的复杂性的需要工作模式。
但是,如果您认为每个查询一个 Query 对象对您来说太过分了,那么您很可能 100% 正确。通常,您可能会选择从“FooQueries”对象开始,它本质上是一个存储库,但仅用于查询。 “Foo”可能是 DDD 意义上的“域聚合”。
然后您可能会发现单个查询对象稍后是有价值的。
与大多数事情一样,您必须逐个系统地考虑。
You should consider "command/query objects" as an alternative, you can find a bunch of interesting articles around this area, but here are some good ones:
https://bigmachine.io/2014/03/04/repositories-and-unitofwork-are-not-a-good-idea/
https://www.dotnetcurry.com/patterns-practices/1461/command-query-separation-cqs
You would stick to a single command object per command to enable simple transactions, avoiding the need for the complexity of the Unit Of Work pattern.
However, if you are thinking a Query object per query is overkill for you, you could well be 100% right. Often you might choose to start with a 'FooQueries' object, which is essentially a Repository but only for Queries. 'Foo' might be your 'domain aggregate' in the DDD sense.
You might then find individual query objects worthwhile later.
As with most things you have to consider on a system by system basis.
软件设计模式旨在在正确的上下文中解决特定问题,如果使用不当,它们会在不提供任何价值的情况下导致额外不必要的复杂性。
那么,存储库模式旨在解决哪些问题解决?
1- 最小化重复查询逻辑:在大型应用程序中,您可能会发现许多复杂的 LINQ 查询在几个地方重复。如果是这种情况,您可以使用存储库模式来封装这些查询并最大程度地减少重复。
2-更好的关注点分离:想象一个复杂的查询,用于获取给定类别中最畅销的课程,其中涉及急切加载、加入、分组、过滤等。
当您在您的应用程序中实现如此大的复杂查询时,服务/控制器,你最终会得到胖服务/控制器。这些类变得很难进行单元测试,因为它们需要大量嘈杂的存根。您的单元测试变得冗长、臃肿且难以维护。
如果您遇到这个问题,也许您可以考虑使用存储库模式。在此示例中,我们可以封装复杂的查询以获取存储库中的最畅销课程:
这样,您的服务/控制器将不再处理急切的加载、加入、分组等。相反,它们将委托给存储库。请记住,急切加载、加入和分组等都是查询逻辑,属于您的数据访问层,而不是您的服务或表示层。
3- 将应用程序架构与持久性框架解耦:当您直接在应用程序中使用实体框架类(例如 DbContext、DbSet 等)时,您的应用程序与实体框架紧密耦合。如果您计划在将来的某个时候切换到不同的 O/RM,甚至是具有不同模型的较新版本的实体框架,您可能必须修改应用程序的许多部分,这可能会导致应用程序中出现新的错误。您可以使用存储库模式将应用程序架构与持久性框架(例如实体框架)分离。这样,您就可以自由地更改为不同的 O/RM,同时将对应用程序的影响降至最低。
观看此视频了解更多详情:
https://youtu.be/rtXpYpZdOzM
Software design patterns are designed to solve specific problems with the right context, and if used inappropriately, they'll lead to extra unnecessary complexity without providing any values.
So, what are the problems that the repository pattern aims to solve?
1- Minimizing duplicate query logic: in large applications, you may find many complex LINQ queries duplicated in a few places. If that's the case, you can use the repository pattern to encapsulate these queries and minimise duplication.
2- Better separation of concerns: Imagine a complex query to get the top selling courses in a given category that involves eager loading, joining, grouping, filtering, etc.
When you implement such large complex queries in your services/controllers, you'll end up with fat services/controllers. These classes become hard to unit test as they'll require a lot of noisy stubbing. Your unit tests become long, fat, and unmaintainable.
If you're facing this problem, perhaps you might consider using the repository pattern. In this example, we can encapsulate the complex query to get top selling courses in a repository:
This way, your services/controller will no longer deal with eager loading, joining, grouping, etc. Instead, they'll delegate to the repository. Remember, eager loading, joining and grouping, etc are querying logic and belongs to your data access layer, not your services or presentation layer.
3- Decoupling your application architecture from persistence frameworks: when you use Entity Framework classes (e.g. DbContext, DbSet, etc) directly in your application, your application is tightly coupled to Entity Framework. If you plan to switch to a different O/RM sometime in the future, or even a newer version of Entity Framework with a different model, you may have to modify many parts of your application and this can lead to new bugs in your application. You can use the repository pattern to decouple your application architecture from persistence frameworks such as Entity Framework. This way, you'll have the freedom to change to a different O/RM with minimal impact on your application.
Check out this video for more details:
https://youtu.be/rtXpYpZdOzM
Martin Fowler 将存储库的角色描述为:“存储库在域和数据映射层之间进行中介,就像内存中的域对象集合一样”。从这个意义上讲,Entity Framework 4.1 公开的是一个存储库。此外,EF 还具有内置的工作统一性。因此,我的建议是忽略您在问题中提到的博客文章。
像这样的代码不仅无用或毫无价值,而且很危险,因为代码中没有添加任何好处,而是依赖!
要回答您的问题,需要在域和数据映射层之间进行一些抽象,就像内存中域对象集合一样,对于“大”项目来说是必须的。在幕后拥有一个 UnitOfWork 机制可以帮助您将业务逻辑与对某些数据访问抽象的访问分离。
TL;TR;
Repository 和 UnitOfWork 可以帮助您,但不要像给定的博客文章中那样应用它。
Martin Fowler describes the repository's role as: "A Repository mediates between the domain and data mapping layers, acting like an in-memory domain object collection". What Entity Framework 4.1 exposes is a repository in that sense. Also EF has a unity of work built in. So my advice is to ignore the blog article you mentioned in your question.
Code like this is not just only useless or worthless but dangerous because there is no benefit added to your code but a dependency!
To answer your question having some abstraction that mediates between the domain and data mapping layers, acting like an in-memory domain object collection is a must for "big" projects. And having a UnitOfWork mechanism under the hood can help decouple your business logic from access to a some data access abstraction.
TL;TR;
Repository and UnitOfWork can help you but don't apply it like in the given blog post.
现在,第一个问题应该是,为什么我需要存储库或工作单元模式?我难道不能只使用控制器中的 EF 上下文,拥有直接编写我需要查询并返回数据?
答案:你可以,但背后的真正意图是可测试性,从而获得更高质量、更易于维护的代码。如果您将数据访问分开并将其集中在一个地方,则可以在测试期间模拟它。这允许您对控制器中定义的逻辑进行单元测试,而无需有效写入数据存储。
在开始工作单元之前,只需查看一下存储库模式。这基本上抽象了给定实体的数据访问。因此,您可以定义 Filter()、All()、Update(..)、Insert(..)、Delete(...) 以及 Save() 等方法。实际上,其中大多数都可以很容易地抽象为
BaseRepository
类,这样最终您只需在极少数具有特殊行为的情况下创建一个新的存储库。否则它会像BaseRepository 一样。 personRepo = new BaseRepository()
或BaseRepository
; addressRepo = new BaseRepository
()
等为什么需要工作单元?
工作单元代表在某个周期内完成的所有操作,在 Web 环境中通常是每个 Http 请求。这意味着当新请求输入时,您实例化一个新的工作单元,添加新内容,更新或删除它,然后通过调用
.save()
或“提交”更改>.commit()
..无论如何。实际上,如果您仔细查看实体框架 DbContext(或 ObjectContext),您会发现它们已经代表了某种工作单元。但是,如果您想进一步抽象它,因为您不一定希望在控制器类中拥有 EF 上下文(记住:可测试性),那么您可以创建一个 UoW 来对您的存储库进行分组,并确保它们都共享相同的 EF上下文实例。您也可以通过 DI 容器(依赖注入容器)来实现后者。
对于您的问题:它在大型项目中有用吗?:
当然,尤其是在大型项目中。这一切都是为了保持职责分离(数据访问、业务逻辑、领域逻辑),从而使事情可测试。
Now, the first question should be, why do I need a repository or unit of work pattern at all? Couldn't I just use the EF context from the controller, having the full power of directly writing the query I need and returning the data?
Answer: You could, but the real intent behind is testability and thus higher quality, more maintainable code. If you separate your data access and concentrate it on one place, you can mock it out during testing. This allows you to unit test the logic defined within your controller without effectively writing to a data store.
Before starting with the Unit of Work, just use take a look at the Repository pattern. This basically abstracts the data access for a given entity. So you define methods like Filter(), All(), Update(..), Insert(..), Delete(...) and finally, Save(). Actually most of these could be quite easily abstracted to a
BaseRepository<TEntity>
class such that in the end you'd just have to create a new Repository in rare cases with special behavior. Otherwise it would be something likeBaseRepository<Person> personRepo = new BaseRepository<Person>()
orBaseRepository<Address> addressRepo = new BaseRepository<Address>()
etc.Why is the Unit of Work needed?
A unit of work represents all operations done during a certain cycle, in a web environment normally per Http request. This means when a new request enters, you instantiate a new Unit of Work, you add new stuff, update or delete it and then you "commit" the changes by invoking the
.save()
or.commit()
..whatever. Actually if you take a closer look at the Entity Framework DbContext (or ObjectContext), they are already representing some kind of Unit of Work.However if you want to further abstract it, because you'd not necessarily like to have your EF context in your controller classes (remember: testability), then you create a UoW to group your Repositories and also to ensure they all share the same EF context instance. You might achieve the latter also through a DI container (Dependency Injection container).
To your questions: Is it useful in big projects?:
Definitely, especially in big projects. It's all about keeping responsibilities separated (data access, business logic, domain logic) and thus making things testable.