使用或不使用存储库与 ORM
To use or not to use Repositories with an ORM
有很多声音说,在这个ORM时代,不再需要存储库了。最近我自己在想,他们的论点对我来说通常是有道理的。
在我使用 EF Core 的新项目中,我想尝试使用无存储库方法来使事情变得更加直接和简单。毕竟,简单总是好的。
事情进展顺利,直到我意识到我经常写这样的东西(这不是真正的聚合,只是一个人为的例子):
ctx.Invoices.Include(x => x.User).ThenInclude(x => x.Address).Include(x => x.Items).FirstOrDefault(x => x.Id == id);
好吧,所以每次我需要得到一个聚合,我都需要写这个语句而且有机会,sometimes/someone会忘记包含一个重要的参考。
如何将这段代码交给助手class?
class InvoiceHelper
{
public Invoice FindById(int id) {...}
}
这不就是一个伪装的仓库的开始吗?因此,即使使用 ORM,我仍然发现存储库很有用。
其他人如何做这些事情并且在没有存储库的情况下仍然看起来很开心?
一些讨论无存储库方法的文章:
如果您相信经验法则 "don't mock what you don't own",我看不出您如何在没有类似存储库的抽象。
存储库是您的应用程序和存储之间的一个非常重要的接缝 - 用六角形术语来说是适配器。
是的,您需要创建一个帮助程序来考虑某些数据获取行为这一事实完美地说明了这种重要性。
[编辑] 关于 "no repos" 文章的想法
与往常一样,大多数 "repository backlash" 是对滥用存储库和 UoW 的过度反应,其根源在于对模式背后的原始原因的集体失忆。
"Why hide a perfectly good framework ?" - EF 不是!
例如,其中一篇文章提到的 IDbSet
是一个行走的漏洞抽象,从它的名字到 Attach()
再到它的所有扩展方法。另请参阅下面对 "perfectly good framework".
提供的 Update()
等方法的误用和误解
相比之下,原始存储库模式的要点是成为一个极简主义的 3 方法类集合抽象,您不会出错。 Add()
、Remove()
和一些 Get 方法是我们所需要的,而不是整个框架的花里胡哨。
"Repository doesn’t make testing any easier" :是的!依赖契约越小,推理、测试和调试就越容易。 A.k.a。吻.
"1. 性能 – sort/filter:Microsoft 的旧(2013)实现 Rep/UoW 有一个名为 GetStudents 的方法 returns IEnumerable。这意味着任何过滤或排序都将在软件中完成,效率低下。"
认真的吗?多年前编写的 Microsoft 教程示例代码的糟糕是整个模式的第一大缺点?当您只需要在 repo 实现中创建一个方法时,它可以根据需要进行优化!
A Rep/UoW 将使用 EF Core 的更新方法更新实体 - 谁说的?又是个稻草人。我已经使用这些模式 10 多年了,从来不需要那种方法。 SaveChanges() 一直是必经之路。
Rep/UoW 的魅力在于您可以编写一个通用存储库,然后使用它来构建所有子存储库
绝对不是。这不是原始模式的一部分,甚至在 DDD 采用早期就被认为是社区中的反模式。
"Option 2 - DDD-styled entity classes"
又名域 类 进行数据访问...这会破坏持久性无知。在我看来这不是一个好主意。
我可以继续讨论那里几乎所有的论点,但要点是:
如果您要责怪某个模式,请在充分理解其基本原理的情况下进行,而不是因为您不喜欢一些被复制粘贴并被几代开发人员崇拜到毫无用处的错误实现.
有很多声音说,在这个ORM时代,不再需要存储库了。最近我自己在想,他们的论点对我来说通常是有道理的。
在我使用 EF Core 的新项目中,我想尝试使用无存储库方法来使事情变得更加直接和简单。毕竟,简单总是好的。
事情进展顺利,直到我意识到我经常写这样的东西(这不是真正的聚合,只是一个人为的例子):
ctx.Invoices.Include(x => x.User).ThenInclude(x => x.Address).Include(x => x.Items).FirstOrDefault(x => x.Id == id);
好吧,所以每次我需要得到一个聚合,我都需要写这个语句而且有机会,sometimes/someone会忘记包含一个重要的参考。
如何将这段代码交给助手class?
class InvoiceHelper
{
public Invoice FindById(int id) {...}
}
这不就是一个伪装的仓库的开始吗?因此,即使使用 ORM,我仍然发现存储库很有用。
其他人如何做这些事情并且在没有存储库的情况下仍然看起来很开心?
一些讨论无存储库方法的文章:
如果您相信经验法则 "don't mock what you don't own",我看不出您如何在没有类似存储库的抽象。
存储库是您的应用程序和存储之间的一个非常重要的接缝 - 用六角形术语来说是适配器。
是的,您需要创建一个帮助程序来考虑某些数据获取行为这一事实完美地说明了这种重要性。
[编辑] 关于 "no repos" 文章的想法
与往常一样,大多数 "repository backlash" 是对滥用存储库和 UoW 的过度反应,其根源在于对模式背后的原始原因的集体失忆。
"Why hide a perfectly good framework ?" - EF 不是! 例如,其中一篇文章提到的
提供的IDbSet
是一个行走的漏洞抽象,从它的名字到Attach()
再到它的所有扩展方法。另请参阅下面对 "perfectly good framework".Update()
等方法的误用和误解相比之下,原始存储库模式的要点是成为一个极简主义的 3 方法类集合抽象,您不会出错。
Add()
、Remove()
和一些 Get 方法是我们所需要的,而不是整个框架的花里胡哨。"Repository doesn’t make testing any easier" :是的!依赖契约越小,推理、测试和调试就越容易。 A.k.a。吻.
"1. 性能 – sort/filter:Microsoft 的旧(2013)实现 Rep/UoW 有一个名为 GetStudents 的方法 returns IEnumerable。这意味着任何过滤或排序都将在软件中完成,效率低下。"
认真的吗?多年前编写的 Microsoft 教程示例代码的糟糕是整个模式的第一大缺点?当您只需要在 repo 实现中创建一个方法时,它可以根据需要进行优化!
A Rep/UoW 将使用 EF Core 的更新方法更新实体 - 谁说的?又是个稻草人。我已经使用这些模式 10 多年了,从来不需要那种方法。 SaveChanges() 一直是必经之路。
Rep/UoW 的魅力在于您可以编写一个通用存储库,然后使用它来构建所有子存储库
绝对不是。这不是原始模式的一部分,甚至在 DDD 采用早期就被认为是社区中的反模式。
"Option 2 - DDD-styled entity classes" 又名域 类 进行数据访问...这会破坏持久性无知。在我看来这不是一个好主意。
我可以继续讨论那里几乎所有的论点,但要点是:
如果您要责怪某个模式,请在充分理解其基本原理的情况下进行,而不是因为您不喜欢一些被复制粘贴并被几代开发人员崇拜到毫无用处的错误实现.