应无所住,而生其心
排名
1
文章
870
粉丝
112
评论
163
net core webapi post传递参数
庸人 : 确实坑哈,我也是下班好了好几次,发现后台传递对象是可以的,但...
百度编辑器自定义模板
庸人 : 我建议换个编辑器,因为现在百度富文本已经停止维护了,用tinymec...
ICP备案 :渝ICP备18016597号-1
网站信息:2018-2025TNBLOG.NET
技术交流:群号656732739
联系我们:contact@tnblog.net
公网安备:50010702506256
欢迎加群交流技术

领域驱动设计DDD ABP VNext 二:使用仓储

10725人阅读 2022/5/21 15:42 总访问:5406363 评论:0 收藏:0 手机
分类: 软件架构

领域驱动设计仓储介绍

在领域层和数据映射层之间进行中介,使用类似集合的接口来操作领域对象.” (Martin Fowler)。

实际上,仓储用于领域对象在数据库(参阅实体)中的操作, 通常每个 聚合根 或不同的实体创建对应的仓储。

换句话说,存储库还处理数据并隐藏类似于DAO的查询。但是,它处于更高的层次,更接近应用程序的业务逻辑。因为我们是领域驱动设计核心在领域而不是数据库,以领域为中心设计,而不是数据为中心。


如果在应用层直接去调用基础设置层的数据库模块操作数据和三层架构没有区别。应该领域层定义仓储,基础设置层的数据库模块比如ef core层实现它。
然后通过领域层的仓储去调用,才是以领域为核心,不是以数据库为核心,因为是通过领域层来操作的数据库,领驱动设计是站在更高的位面来思考问题,不要一来就深入到繁杂的数据库这样的细节设计中去,操作数据库的只是基础设施层中用来操作数据库,做数据持久化的,至于持久化模块用什么就是基础设施层的事情了,其实领域层不需要去关心这些细节。

领域驱动设计DDD聚合模式的理解可以参考:
https://www.tnblog.net/notebook/article/details/7146

使用ABP VNext封装的通用仓储

abp vnext为每个聚合根或实体提供了 默认的通用仓储,通用仓储提供了一些开箱即用的标准CRUD功能。可以直接注入使用,里边基础的一些crud操作都已经封装好了直接使用即可,还是可以帮我们减少一些工作量。


这种没有什么技术含量的工作,就应该封装一次重复使用。而且还能更标准化,不然一个团队里边每个人按自己的想法命名写一套,就很乱了,这也是为什么一个项目讲过多个人之手后,变得….难以维护的原因,缺乏良好的架构和标准化。

使用ABP VNext封装的通用仓储非常简单,直接注入即可

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6. using Volo.Abp.Application.Services;
  7. using Volo.Abp.Domain.Repositories;
  8. using WY.JBLand.Application.User.Dto;
  9. using WY.JBLand.Domain.User;
  10. using WY.JBLand.EntityFrameworkCore;
  11. namespace WY.JBLand.Application.User
  12. {
  13. public class UserInfoAppService : ApplicationService, IUserInfoAppService
  14. {
  15. private readonly WyJBLandDbContext _wyJBLandDbContext;
  16. /// 使用ABP VNext封装的通用仓储
  17. private readonly IRepository<UserInfo> _userinfoRepository;
  18. public UserInfoAppService(WyJBLandDbContext wyJBLandDbContext, IRepository<UserInfo> userinfoRepository)
  19. {
  20. _wyJBLandDbContext = wyJBLandDbContext;
  21. _userinfoRepository = userinfoRepository;
  22. }
  23. public async Task<List<UserInfoDTO>> GetListAsync()
  24. {
  25. List<UserInfo> userInfos = await _userinfoRepository.GetListAsync();
  26. var result = ObjectMapper.Map<List<UserInfo>, List<UserInfoDTO>>(userInfos);
  27. return null;
  28. }
  29. public List<UserInfoDTO> Get()
  30. {
  31. List<UserInfo> userInfos = _wyJBLandDbContext.UserInfo.ToList();
  32. //使用AutoMapper进行对象转换
  33. var result = ObjectMapper.Map<List<UserInfo>, List<UserInfoDTO>>(userInfos);
  34. return result;
  35. }
  36. }
  37. }

还要注意基础设置层中上下文对象注入的时候加上options.AddDefaultRepositories(true);不然不会生成默认的仓储,注入是空会报错

还有一个坑是依赖注入要使用autofac,不然操作起来也是为空的哦

只读仓储

对于想要使用只读仓储的开发者,使用IReadOnlyRepository 与 IReadOnlyBasicRepository接口即可。

自定义仓储

对于大多数情况, 默认通用仓储就足够了. 但是, 你可能会需要为实体创建自定义仓储类。

ABP不会强制你实现任何接口或从存储库的任何基类继承. 它可以只是一个简单的POCO类. 但是建议继承现有的仓储接口和类, 获得开箱即用的标准方法使你的工作更轻松。

自定义仓储接口

首先在领域层定义一个仓储接口:

  1. public interface IPersonRepository : IRepository<Person, Guid>
  2. {
  3. Task<Person> FindByNameAsync(string name);
  4. }

此接口扩展了 IRepository 以使用已有的通用仓储功能.

实现自定义的仓储接口

在数据库访问层中实现上面写的接口

自定义存储库依赖于你使用的数据访问工具. 在此示例中, 我们将使用Entity Framework Core:

  1. public class PersonRepository : EfCoreRepository<MyDbContext, Person, Guid>, IPersonRepository
  2. {
  3. public PersonRepository(IDbContextProvider<TestAppDbContext> dbContextProvider)
  4. : base(dbContextProvider)
  5. {
  6. }
  7. public async Task<Person> FindByNameAsync(string name)
  8. {
  9. return await DbContext.Set<Person>()
  10. .Where(p => p.Name == name)
  11. .FirstOrDefaultAsync();
  12. }
  13. }

大概的结构如下:

IQueryable & 异步操作

IRepository 继承自 IQueryable,这意味着你可以直接使用LINQ扩展方法. 如上面的泛型仓储示例.

示例: 使用 Where(…) 和 ToList() 扩展方法

  1. var people = _personRepository
  2. .Where(p => p.Name.Contains(nameFilter))
  3. .ToList();

通常想要使用.ToListAsync(), .CountAsync()…. 来编写真正的异步代码.

但在你使用标准的应用程序启动模板时会发现无法在应用层或领域层使用这些异步扩展方法,因为:

  • 这里异步方法不是标准LINQ方法,它们定义在Microsoft.EntityFrameworkCoreNuget包中。
  • 标准模板应用层与领域层不引用EF Core 包以实现数据库提供程序独立.
    根据你的需求和开发模式,你可以根据以下选项使用异步方法。


强烈建议使用异步方法! 在执行数据库查询时不要使用同步LINQ方法,以便能够开发可伸缩的应用程序.


欢迎加群讨论技术,1群:677373950(满了,可以加,但通过不了),2群:656732739。有需要软件开发,或者学习软件技术的朋友可以和我联系~(Q:815170684)

评价

领域驱动设计DDD的一点理解

有人误认为项目架构中加入xxRepository,xxDomain,xxValueObject就变成了DDD架构。如果没有悟出其精髓就在项目中加入这些...

领域驱动设计DDD ABP VNext项目架构搭建,模块使用

[TOC]用户接口层改造nuget中下载abp依赖VoLo.Abp.AspNetCore.Mvc ItemGroup添加方式 &lt;ItemGroup&gt; &lt;Packa...

领域驱动设计DDD之Repository

DDD中的Repository模式Repository模式也称存储库模式或仓储模式,根据Eric Evans的《领域驱动设计》一书,“存储库是一种封...

领域驱动设计DDD ABP VNext领域模型 之 失血模型,贫血模型,充血模型,胀血模型

[TOC]领域模型分为:失血模型,贫血模型,充血模型,胀血模型。 一、失血模型传统的三层架构,实体对象就是简单的POJO或者...

领域驱动设计,概念的理解

[TOC]领域服务(Domain Service)领域中的一些概念不太适合建模为对象,即归类到实体对象或值对象,因为它们本质上就是一些...

Idea下使用maven搭建SSM()MyBatis

开发Web应用,数据的存储和处理往往离不开数据库和SQL语句。在使用Java开发的Web应用中,自然也少不了连接数据库的步骤。在...

Layui水平级菜单时长不显示的问题

调用一下初始化方法Init就可以解决了

Python实例 2-12306抢票() 下单

第二篇 刷票与下单1.记住登陆上一篇写了登陆:http://www.tnblog.net/cz/article/details/162 为了方便调试 不让每次登陆都...

c使用unity实现依赖注入:基本使用

使用Unity实现依赖注入的基本步骤:1:需要创建一个容器2:给容器添加类与类之间的关系(控制反转)3: 在需要的地方从容器里...

c webservice基本分布式访问

使用webservice接口有个好处就是可以分布式访问。例如我们在玩游戏的时候先要选择一个区,然后在进入游戏。这样是因为如果...

级域名解析到服务器的不同端口上

一般二级域名都是解析到不同的服务器上,但是很多时候没有那么土豪可以用那么多服务器哇。所以想把二级域名解析到和主域名...

C与Java进制编码转换,补码

在C#与Java接口对接时,需要将图片转化为二进制编码传输,这时候发现c#转换出来的编码的值是0~255的范围,而java方需要的是...

使用nginx在同一台服务器上配置多个级域名

一般二级域名都是解析到不同的服务器上,但是很多时候没有那么土豪可以用那么多服务器哇。当然土豪完全可以1个二级域名一台...

rabbitmq官网上六大版块之(Direct类型交换机通过routingKey分类型输出)

其实rabbitmq,老师都说得差不多了,下面是老师的连接。http://www.tnblog.net/aojiancc2/article/UserCategory/134官网教...

vue.js 学习日记第章-在vue中编写function及一些简单指令

官网:https://cn.vuejs.org/v2/guide/ vue.js 学习日记第一章:http://www.tnblog.net/18323015640/article/details/2...