不使用存储库模式,按原样使用 ORM (EF) [英] NOT using repository pattern, use the ORM as is (EF)

查看:20
本文介绍了不使用存储库模式,按原样使用 ORM (EF)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直使用 Repository 模式,但对于我的最新项目,我想看看我是否可以完善它的使用以及我对工作单元"的实现.我开始挖掘的越多,我就开始问自己这个问题:我真的需要它吗?"

现在这一切都始于 Stackoverflow 上的几条评论,以及 Ayende Rahien 在他博客上的帖子的痕迹,其中有 2 个具体的,

这可能会永远被谈论,这取决于不同的应用程序.我想知道什么,

  1. 这种方法是否适合实体框架项目?
  2. 使用这种方法的业务逻辑是否仍在服务层或扩展方法中(如下所述,我知道,扩展方法使用 NHib 会话)?

使用扩展方法很容易做到这一点.干净、简单且可重复使用.

public static IEnumerable GetAll(这个 ISession 实例,Expression<Func<T, bool>>where) where T : 类{返回 instance.QueryOver().Where(where).List();}

使用这种方法和 Ninject 作为 DI,我是否需要使 Context 成为一个接口并将其注入我的控制器中?

解决方案

我已经走了很多路,并在不同的项目中创建了许多存储库的实现......我已经放弃并放弃了,这就是为什么.

异常编码

您是否为您的数据库从一种技术更改为另一种技术的 1% 机会编码?如果您正在考虑您的业务的未来状态并说是的,这是一种可能性,那么 a) 他们必须有很多钱来负担迁移到另一种数据库技术或 b) 您选择数据库技术是为了好玩或 c) 您决定使用的第一种技术出现了严重错误.

为什么要丢弃丰富的 LINQ 语法?

LINQ 和 EF 被开发出来,所以你可以用它来做一些巧妙的事情来读取和遍历对象图.创建和维护一个可以为您提供相同灵活性的存储库是一项艰巨的任务.根据我的经验,每次创建存储库时,我总是会将业务逻辑泄漏到存储库层,以提高查询性能和/或减少对数据库的点击次数.>

我不想为我必须编写的查询的每一个排列都创建一个方法.我还不如写存储过程.我不想要 GetOrderGetOrderWithOrderItemGetOrderWithOrderItemWithOrderActivityGetOrderByUserId 等等......我只想要获取主要实体并按照我的意愿遍历并包含对象图.

大多数存储库示例都是废话

除非您正在开发一些真正简单的东西,例如博客或其他东西,否则您的查询永远不会像您在互联网上找到的围绕存储库模式的 90% 的示例一样简单.我怎么强调都不过分!这是人们必须在泥泞中爬行才能弄清楚的事情.总会有一个查询会破坏您创建的经过深思熟虑的存储库/解决方案,直到您再次猜测自己并开始技术债务/侵蚀.

兄弟不要对我进行单元测试

但是如果我没有存储库,单元测试怎么办?我将如何嘲笑?很简单,你没有.让我们从两个角度来看:

没有存储库 - 您可以使用 IDbContext 或其他一些技巧来模拟 DbContext,但您实际上是在单元测试 LINQ to Objects而不是LINQ to Entities,因为查询是在运行时确定的……好吧,这样不好!所以现在由集成测试来覆盖这个.

使用存储库 - 您现在可以模拟存储库并对中间的层进行单元测试.很棒吧?不是真的......在上面的情况下,您必须将逻辑泄漏到存储库层以提高查询的性能和/或减少对数据库的命中,您的单元测试如何覆盖它?它现在在 repo 层中,您不想测试 IQueryable 对吗?另外,老实说,您的单元测试不会涵盖具有 20 行 .Where() 子句和 .Include() 一堆关系的查询并再次访问数据库以执行所有其他操作,等等,等等,等等,因为查询是在运行时生成的.此外,由于您创建了一个存储库以保持上层持久性无知,如果您现在想要更改数据库技术,很抱歉,您的单元测试肯定不会保证在运行时获得相同的结果,回到集成测试.所以存储库的整个点看起来很奇怪..

2 美分

在普通存储过程(批量插入、批量删除、CTE 等)上使用 EF 时,我们已经失去了很多功能和语法,但我也在 C# 中编码,所以我不必键入二进制.我们使用 EF,因此我们可以使用不同的提供者,并在许多事情中以一种很好的相关方式使用对象图.某些抽象很有用,有些则没有.

I always used Repository pattern but for my latest project I wanted to see if I could perfect the use of it and my implementation of "Unit Of Work". The more I started digging I started asking myself the question: "Do I really need it?"

Now this all starts with a couple of comments on Stackoverflow with a trace to Ayende Rahien's post on his blog, with 2 specific,

This could probably be talked about forever and ever and it depends on different applications. Whats I like to know,

  1. would this approach be suited for a Entity Framework project?
  2. using this approach is the business logic still going in a service layer, or extension methods (as explained below, I know, the extension method is using NHib session)?

That's easily done using extension methods. Clean, simple and reusable.

public static IEnumerable GetAll(
    this ISession instance, Expression<Func<T, bool>> where) where T : class
{
    return instance.QueryOver().Where(where).List();
}

Using this approach and Ninject as DI, do I need to make the Context a interface and inject that in my controllers?

解决方案

I've gone down many paths and created many implementations of repositories on different projects and... I've thrown the towel in and given up on it, here's why.

Coding for the exception

Do you code for the 1% chance your database is going to change from one technology to another? If you're thinking about your business's future state and say yes that's a possibility then a) they must have a lot of money to afford to do a migration to another DB technology or b) you're choosing a DB technology for fun or c) something has gone horribly wrong with the first technology you decided to use.

Why throw away the rich LINQ syntax?

LINQ and EF were developed so you could do neat stuff with it to read and traverse object graphs. Creating and maintain a repository that can give you the same flexibility to do that is a monstrous task. In my experience any time I've created a repository I've ALWAYS had business logic leak into the repository layer to either make queries more performant and/or reduce the number of hits to the database.

I don't want to create a method for every single permutation of a query that I have to write. I might as well write stored procedures. I don't want GetOrder, GetOrderWithOrderItem, GetOrderWithOrderItemWithOrderActivity, GetOrderByUserId, and so on... I just want to get the main entity and traverse and include the object graph as I so please.

Most examples of repositories are bullshit

Unless you are developing something REALLY bare-bones like a blog or something your queries are never going to be as simple as 90% of the examples you find on the internet surrounding the repository pattern. I cannot stress this enough! This is something that one has to crawl through the mud to figure out. There will always be that one query that breaks your perfectly thought out repository/solution that you've created, and it's not until that point where you second guess yourself and the technical debt/erosion begins.

Don't unit test me bro

But what about unit testing if I don't have a repository? How will I mock? Simple, you don't. Lets look at it from both angles:

No repository - You can mock the DbContext using an IDbContext or some other tricks but then you're really unit testing LINQ to Objects and not LINQ to Entities because the query is determined at runtime... OK so that's not good! So now it's up to the integration test to cover this.

With repository - You can now mock your repositories and unit test the layer(s) in between. Great right? Well not really... In the cases above where you have to leak logic into the repository layer to make queries more performant and/or less hits to the database, how can your unit tests cover that? It's now in the repo layer and you don't want to test IQueryable<T> right? Also let's be honest, your unit tests aren't going to cover the queries that have a 20 line .Where() clause and .Include()'s a bunch of relationships and hits the database again to do all this other stuff, blah, blah, blah anyways because the query is generated at runtime. Also since you created a repository to keep the upper layers persistence ignorant, if you now you want to change your database technology, sorry your unit tests are definitely not going to guarantee the same results at runtime, back to integration tests. So the whole point of the repository seems weird..

2 cents

We already lose a lot of functionality and syntax when using EF over plain stored procedures (bulk inserts, bulk deletes, CTEs, etc.) but I also code in C# so I don't have to type binary. We use EF so we can have the possibility of using different providers and to work with object graphs in a nice related way amongst many things. Certain abstractions are useful and some are not.

这篇关于不使用存储库模式,按原样使用 ORM (EF)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆