河南建设教育中心网站,做轻奢品的电商网站,传世网站建设,Wordpress怎么配合HTML上一篇文章我们用Code-First的方式创建了博客所需的实体类#xff0c;生成了数据库表#xff0c;完成了对EF Core的封装。本篇说一下自定义仓储的实现方式#xff0c;其实在abp框架中已经默认给我们实现了默认的通用(泛型)仓储#xff0c;IRepositoryTEntity, TKey… 上一篇文章我们用Code-First的方式创建了博客所需的实体类生成了数据库表完成了对EF Core的封装。本篇说一下自定义仓储的实现方式其实在abp框架中已经默认给我们实现了默认的通用(泛型)仓储IRepositoryTEntity, TKey有着标准的CRUD操作可以看https://docs.abp.io/zh-Hans/abp/latest/Repositories 学习更多。之所以实现自定义仓储是因为abp没有给我们实现批量插入、更新的方法这个是需要自己去扩展的。既然是自定义仓储那么就有了很高的自由度我们可以任意发挥可以接入第三方批量处理数据的库可以接入Dapper操作等等在这里贴一下微软官方推荐的一些EF Core的工具和扩展https://docs.microsoft.com/zh-cn/ef/core/extensions/ 。自定义仓储在.Domain领域层中创建仓储接口IPostRepository、ICategoryRepository、ITagRepository、IPostTagRepository、IFriendLinkRepository这里直接全部继承 IRepositoryTEntity, TKey 以使用已有的通用仓储功能。可以转到IRepositoryTEntity, TKey接口定义看一下看看abp对于仓储的介绍如下IRepositoryTEntity, TKey 接口扩展了标准 IQueryableTEntity 你可以使用标准LINQ方法自由查询。但是某些ORM提供程序或数据库系统可能不支持IQueryable接口。ABP提供了 IBasicRepositoryTEntity, TPrimaryKey 和 IBasicRepositoryTEntity 接口来支持这样的场景。你可以扩展这些接口并可选择性地从BasicRepositoryBase派生为你的实体创建自定义存储库。依赖于 IBasicRepository 而不是依赖 IRepository 有一个优点, 即使它们不支持 IQueryable 也可以使用所有的数据源, 但主要的供应商, 像 Entity Framework, NHibernate 或 MongoDb 已经支持了 IQueryable。因此, 使用 IRepository 是典型应用程序的 建议方法。但是可重用的模块开发人员可能会考虑使用 IBasicRepository 来支持广泛的数据源。对于想要使用只读仓储提供了IReadOnlyRepositoryTEntity, TKey 与 IReadOnlyBasicRepositoryTentity, TKey接口。仓储接口类如下//IPostRepository.cs
using Volo.Abp.Domain.Repositories;namespace Meowv.Blog.Domain.Blog.Repositories
{/// summary/// IPostRepository/// /summarypublic interface IPostRepository : IRepositoryPost, int{}
}
//ICategoryRepository.cs
using Volo.Abp.Domain.Repositories;namespace Meowv.Blog.Domain.Blog.Repositories
{/// summary/// ICategoryRepository/// /summarypublic interface ICategoryRepository : IRepositoryCategory, int{}
}
//ITagRepository.cs
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Domain.Repositories;namespace Meowv.Blog.Domain.Blog.Repositories
{/// summary/// ITagRepository/// /summarypublic interface ITagRepository : IRepositoryTag, int{/// summary/// 批量插入/// /summary/// param nametags/param/// returns/returnsTask BulkInsertAsync(IEnumerableTag tags);}
}
//IPostTagRepository.cs
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Domain.Repositories;namespace Meowv.Blog.Domain.Blog.Repositories
{/// summary/// IPostTagRepository/// /summarypublic interface IPostTagRepository : IRepositoryPostTag, int{/// summary/// 批量插入/// /summary/// param namepostTags/param/// returns/returnsTask BulkInsertAsync(IEnumerablePostTag postTags);}
}
//IFriendLinkRepository.cs
using Volo.Abp.Domain.Repositories;namespace Meowv.Blog.Domain.Blog.Repositories
{/// summary/// IFriendLinkRepository/// /summarypublic interface IFriendLinkRepository : IRepositoryFriendLink, int{}
}
在ITagRepository和IPostTagRepository仓储接口中我们添加了批量插入的方法。相对于的在我们的.EntityFrameworkCore层实现这些接口。创建Repositories/Blog 文件夹添加实现类PostRepository、CategoryRepository、TagRepository、PostTagRepository、FriendLinkRepository。不知道大家发现没有我们的仓储接口以及实现都是以Repository结尾的这和我们的.Application应用服务层都以Service结尾是一个道理。在自定义仓储的实现中我们可以使用任意你想使用的数据访问工具我们这里还是继续用Entity Framework Core需要继承EfCoreRepositoryTDbContext, TEntity, TKey和我们的仓储接口IXxxRepository。EfCoreRepository默认实现了许多默认的方法然后就可以直接使用 DbContext 来执行操作了。仓储接口实现类如下//PostRepository.cs
using Meowv.Blog.Domain.Blog;
using Meowv.Blog.Domain.Blog.Repositories;
using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore;namespace Meowv.Blog.EntityFrameworkCore.Repositories.Blog
{/// summary/// PostRepository/// /summarypublic class PostRepository : EfCoreRepositoryMeowvBlogDbContext, Post, int, IPostRepository{public PostRepository(IDbContextProviderMeowvBlogDbContext dbContextProvider) : base(dbContextProvider){}}
}
//CategoryRepository.cs
using Meowv.Blog.Domain.Blog;
using Meowv.Blog.Domain.Blog.Repositories;
using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore;
namespace Meowv.Blog.EntityFrameworkCore.Repositories.Blog
{/// summary/// CategoryRepository/// /summarypublic class CategoryRepository : EfCoreRepositoryMeowvBlogDbContext, Category, int, ICategoryRepository{public CategoryRepository(IDbContextProviderMeowvBlogDbContext dbContextProvider) : base(dbContextProvider){}}
}
//TagRepository.cs
using Meowv.Blog.Domain.Blog;
using Meowv.Blog.Domain.Blog.Repositories;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore;namespace Meowv.Blog.EntityFrameworkCore.Repositories.Blog
{/// summary/// TagRepository/// /summarypublic class TagRepository : EfCoreRepositoryMeowvBlogDbContext, Tag, int, ITagRepository{public TagRepository(IDbContextProviderMeowvBlogDbContext dbContextProvider) : base(dbContextProvider){}/// summary/// 批量插入/// /summary/// param nametags/param/// returns/returnspublic async Task BulkInsertAsync(IEnumerableTag tags){await DbContext.SetTag().AddRangeAsync(tags);await DbContext.SaveChangesAsync();}}
}
//PostTagRepository.cs
using Meowv.Blog.Domain.Blog;
using Meowv.Blog.Domain.Blog.Repositories;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore;namespace Meowv.Blog.EntityFrameworkCore.Repositories.Blog
{/// summary/// PostTagRepository/// /summarypublic class PostTagRepository : EfCoreRepositoryMeowvBlogDbContext, PostTag, int, IPostTagRepository{public PostTagRepository(IDbContextProviderMeowvBlogDbContext dbContextProvider) : base(dbContextProvider){}/// summary/// 批量插入/// /summary/// param namepostTags/param/// returns/returnspublic async Task BulkInsertAsync(IEnumerablePostTag postTags){await DbContext.SetPostTag().AddRangeAsync(postTags);await DbContext.SaveChangesAsync();}}
}
//FriendLinkRepository.cs
using Meowv.Blog.Domain.Blog;
using Meowv.Blog.Domain.Blog.Repositories;
using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore;namespace Meowv.Blog.EntityFrameworkCore.Repositories.Blog
{/// summary/// PostTagRepository/// /summarypublic class FriendLinkRepository : EfCoreRepositoryMeowvBlogDbContext, FriendLink, int, IFriendLinkRepository{public FriendLinkRepository(IDbContextProviderMeowvBlogDbContext dbContextProvider) : base(dbContextProvider){}}
}
在TagRepository和PostTagRepository仓储接口的实现中因为数据量不大可以直接用了EF Core自带的AddRangeAsync批量保存数据。到这里关于博客的自定义仓储便完成了此时项目层级目录图如下增删改查接下来在就可以在.Application服务层愉快的玩耍了写服务之前我们要分析我们的项目要有哪些功能业务。由于是博客项目无非就是一些增删改查。今天先不写博客业务先完成对数据库文章表meowv_posts的一个简单CRUD。在.Application层新建Blog文件夹添加一个IBlogService.cs博客接口服务类分别添加增删改查四个方法。这时就要用到我们的数据传输对象(DTO)了简单理解DTO就是从我们的领域模型中抽离出来的对象它是很纯粹的只包含我们拿到的数据不参杂任何行为逻辑。在.Application.Contracts层新建Blog文件夹同时新建一个PostDto.cs类与.Domain层中的Post.cs与之对应他们很相似但是不一样。于是IBlogService.cs接口服务类的CRUD为//IBlogService.cs
using Meowv.Blog.Application.Contracts.Blog;
using System.Threading.Tasks;namespace Meowv.Blog.Application.Blog
{public interface IBlogService{Taskbool InsertPostAsync(PostDto dto);Taskbool DeletePostAsync(int id);Taskbool UpdatePostAsync(int id, PostDto dto);TaskPostDto GetPostAsync(int id);}
}
接口写好了少不了实现方式直接在Blog文件夹新建Impl文件夹用来存放我们的接口实现类BlogService.cs注意都是以Service结尾的噢~实现服务接口除了要继承我们的IBlogService外不要忘了还需依赖我们的ServiceBase类。由于我们之前直接接入了Autofac可以直接使用构造函数依赖注入的方式。//BlogService.cs
using Meowv.Blog.Application.Contracts.Blog;
using Meowv.Blog.Domain.Blog.Repositories;
using System;
using System.Threading.Tasks;namespace Meowv.Blog.Application.Blog.Impl
{public class BlogService : ServiceBase, IBlogService{private readonly IPostRepository _postRepository;public BlogService(IPostRepository postRepository){_postRepository postRepository;}...}
}
现在就可以实现我们写的IBlogService接口了。先写添加这里实现方式全采用异步的方法先构建一个Post实体对象具体内容参数都从PostDto中获取由于主键之前设置了自增这里就不用管它了。然后调用 await _postRepository.InsertAsync(entity);正好它返回了一个创建成功的Post对象那么我们就可以判断对象是否为空从而确定文章是否添加成功。代码如下...public async Taskbool InsertPostAsync(PostDto dto){var entity new Post{Title dto.Title,Author dto.Author,Url dto.Url,Html dto.Html,Markdown dto.Markdown,CategoryId dto.CategoryId,CreationTime dto.CreationTime};var post await _postRepository.InsertAsync(entity);return post ! null;}
...
然后在.HttpApi层和之前添加HelloWorldController一样添加BlogController。调用写的InsertPostAsync方法如下//BlogController.cs
using Meowv.Blog.Application.Blog;
using Meowv.Blog.Application.Contracts.Blog;
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;
using Volo.Abp.AspNetCore.Mvc;namespace Meowv.Blog.HttpApi.Controllers
{[ApiController][Route([controller])]public class BlogController : AbpController{private readonly IBlogService _blogService;public BlogController(IBlogService blogService){_blogService blogService;}/// summary/// 添加博客/// /summary/// param namedto/param/// returns/returns[HttpPost]public async Taskbool InsertPostAsync([FromBody] PostDto dto){return await _blogService.InsertPostAsync(dto);}}
}
添加博客操作我们将其设置为[HttpPost]方式来提交因为现在开发接口api都要遵循RESTful方式所以就不用给他指定路由了[FromBody]的意思是在请求正文中以JSON的方式来提交参数。完成上述操作打开我们的Swagger文档看看 .../swagger/index.html 已经出现我们的接口了。随手就试一下这个接口能否成功创建文章。可以看到数据库已经躺着我们刚刚添加数据内容。将剩下的三个接口一一实现相信大家肯定都知道怎么写了。就不逐一唠叨了代码如下...public async Taskbool DeletePostAsync(int id){await _postRepository.DeleteAsync(id);return true;}public async Taskbool UpdatePostAsync(int id, PostDto dto){var post await _postRepository.GetAsync(id);post.Title dto.Title;post.Author dto.Author;post.Url dto.Url;post.Html dto.Html;post.Markdown dto.Markdown;post.CategoryId dto.CategoryId;post.CreationTime dto.CreationTime;await _postRepository.UpdateAsync(post);return true;}public async TaskPostDto GetPostAsync(int id){var post await _postRepository.GetAsync(id);return new PostDto{Title post.Title,Author post.Author,Url post.Url,Html post.Html,Markdown post.Markdown,CategoryId post.CategoryId,CreationTime post.CreationTime};}
...
在这里先暂时不做参数校验咱们默认都是正常操作如果执行操作成功直接返回true。大家会发现当我们使用了DTO后写了大量对象的转换在这里暂不做优化将在后续业务开始后使用AutoMapper处理对象映射。如果大家感兴趣可以自己先试一下。在Controller中调用代码如下.../// summary/// 删除博客/// /summary/// param nameid/param/// returns/returns[HttpDelete]public async Taskbool DeletePostAsync([Required] int id){return await _blogService.DeletePostAsync(id);}/// summary/// 更新博客/// /summary/// param nameid/param/// param namedto/param/// returns/returns[HttpPut]public async Taskbool UpdatePostAsync([Required] int id, [FromBody] PostDto dto){return await _blogService.UpdatePostAsync(id, dto);}/// summary/// 查询博客/// /summary/// param nameid/param/// returns/returns[HttpGet]public async TaskPostDto GetPostAsync([Required] int id){return await _blogService.GetPostAsync(id);}
...
DeletePostAsync指定了请求方式[HttpDelete]参数id为必填项UpdatePostAsync指定了请求方式[HttpPut]参数id为必填项并且为url的一部分要更新的具体内容和添加博客的方法InsertPostAsync的一样的GetPostAsync指定了请求方式[HttpGet]参数id为必填项ok打开Swagger文档看看效果并试试我们的接口是否好使吧反正我试了是没有问题的。做到这一步的项目层级目录如下:本篇使用自定义仓储的方式完成了对博客(meowv_posts)的增删改查你学会了吗????????????开源地址https://github.com/Meowv/Blog/tree/blog_tutorial