这是我参与8月更文挑战的第8天,活动详情查看:8月更文挑战
- 📢欢迎点赞 :👍 收藏 ⭐留言 📝 如有错误敬请指正,赐人玫瑰,手留余香!
- 📢本文作者:由webmote 原创,首发于 【CSDN】
- 📢作者格言: 生活在于折腾,当你不折腾生活时,生活就开始折腾你,让我们一起加油!💪💪💪
🎏 序言
大家都知道,ORM(实体关系映射模型)能帮助我们快速构建应用程序,而在使用.net 技术栈工作时,一定会首选Microsoft的数据库访问框架Entity Framework Core(EF Core)来构建应用程序,这里我们就谈谈你们中许多人都熟悉的软件原理和模式。 如果对前三种原则感兴趣的可以发翻看第一篇文章。
🎏1.仓储
我们可以通过多种不同的方式访问数据库,并从其他应用程序隐藏EF访问层。在下图中,我显示了四种不同的数据访问模式。
四种类型的数据库访问模式是:
- 仓储+工作单元(Repo + UOW): 这会将所有EF Core隐藏在为EF提供不同接口的代码后面。您可以用另一个数据库访问框架替换EF,而无需更改调用Repo + UOW的方法。
- EF仓储: 这是一个仓储模式,它不会像Repo + UOW模式那样尝试隐藏EF代码。EF仓储假定您作为开发人员知道EF的规则,例如使用跟踪的实体并调用SaveChanges进行更新,因此您将遵守它们。
- 查询对象: 查询对象封装了数据库查询(即数据库读取)的代码。它们保存了查询的整个代码,或者包含了查询部分的复杂查询。查询对象通常使用IQueryable 输入和输出作为扩展方法构建,以便可以将它们链接在一起以构建更复杂的查询。
- 直接调用EF。这表示您只是将所需的EF代码放在需要它的方法中的情况。
Repo + UOW模式,虽然是很多人推荐的方法,但太重了,不建议使用。直接调用EF,无法分离关注点,一般也不推荐。
因此,在排除了两个极端之后,我建议:
- 查询对象,通常将大型查询分解为一系列查询对象
- 对于“创建,更新和删除”,我使用DDD风格的访问方法,即,我在实体类中创建了一个方法来更新属性或关系。这样可以隔离EF代码,并使重构或性能优化变得更加容易。
public class ChangePubDateService : IChangePubDateService
{
private readonly EfCoreContext _context;
public ChangePubDateService(EfCoreContext context)
{
_context = context;
}
public ChangePubDateDto GetOriginal(int id)
{
return _context.Books
.Select(p => new ChangePubDateDto
{
BookId = p.BookId,
Title = p.Title,
PublishedOn = p.PublishedOn
})
.Single(k => k.BookId == id);
}
public Book UpdateBook(ChangePubDateDto dto)
{
var book = _context.Books.Find(dto.BookId);
book.PublishedOn = dto.PublishedOn;
_context.SaveChanges();
return book;
}
}
🎏2.依赖注入
.NetCore 完全支持依赖注入(DI),你也应该顺应时代了。
- 将每个数据库访问代码都放入仓储库中。
- 为每个EF存储库类添加一个接口。
- 在DI提供程序中针对其接口注册EF存储库类。
- 然后,您需要将其注入到需要它的前端方法中。
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult ChangePubDate(ChangePubDateDto dto,
[FromServices]IChangePubDateService service)
{
service.UpdateBook(dto);
return View("BookUpdated",
"Successfully changed publication date");
}
🎏3.建立业务逻辑
实际应用的构建是为了提供某种服务,范围从在计算机上保存文件到管理核反应堆。
现实世界中每个不同的问题都有一组规则,通常称为业务规则,或更通用的名称,称为领域规则。
太多人提DDD了,你可以查阅大量的实践文章,这里只讲一点:
您要解决的业务问题必须驱动整个开发。
关于EF Core是否适用于DDD方法存在很多争论,因为业务逻辑代码通常与映射到数据库的EF实体类是分开的。我们开发时的一大原则是:“不要与您的框架作斗争,寻求保持领域驱动设计的方法,并在框架处于敌对状态时放弃细节”。
- 重点考虑业务逻辑,定义好数据库结构,解决领域模型和EF模型的出入。
- 业务逻辑不应分心,编写业务逻辑本身就很困难,将其与除实体类之外的所有其他应用程序层隔离。当编写业务逻辑时,只需要考虑要解决的业务问题。
- 业务逻辑应该认为它正在处理内存数据
- 将数据库访问代码隔离到一个单独的项目中
- 业务逻辑不应直接调用EF Core的SaveChanges
🎏4.使您的EF代码正常工作,然后需要时优化它。
开发的原则是使其工作!
无论哪种方式,这些原则都表明我们应该将性能调优放到最后,并仅在需要时才调整性能。
快速的在EF中开发复杂的数据库访问-至少比使用ADO.NET或Dapper快五倍。不利的一面是EF并不总是会产生性能最好的SQL命令:有时是因为EF没有提供良好的SQL转换,有时是因为我编写的LINQ代码效率不如我想象的那样。
问题是:这有关系吗?
当然优化是需要代价的,后面展示了如何在一系列阶段中改进,每个阶段都变得越来越复杂,并且花费了更多的开发时间:
- 通过重新排列或完善EF代码来改善基本的EF命令吗?
- 将部分或全部EF代码转换为直接SQL命令,计算所得的列,存储过程等吗?
- 是否可以更改数据库结构(例如对数据库进行非规范化)以提高搜索性能?
规划可能的性能调整
尽管我完全同意过早进行性能调整的想法,但是明智的做法是提前计划您可能的性能调整。
🎏5.结论
每一种技术都是越来越难,因为学习任何新技术都需要花费一些时间才能使其变得平滑自然。
已经有许多伟大的软件思想家,还有一些伟大的原理和实践。因此,当下次我们想做的更好时,不妨去看看其他人的想法。
哦哦,祝您编码愉快!
例行小结,理性看待。
👓都看到这了,还在乎点个赞吗?
👓都点赞了,还在乎一个收藏吗?
👓都收藏了,还在乎一个评论吗?