已经可以查询出数据,并且缓存至Redis中。
获取文章详情分析:文章详情页,文章的标题、作者、发布时间、所属分类、标签列表、文章内容(HTML和MarkDown)、链接、上下篇的标题和链接。
创建返回模型:PostDetailDto.cs
//PostDetailDto.cs using System.Collections.Generic; namespace Meowv.Blog.Application.Contracts.Blog { public class PostDetailDto { /// <summary> /// 标题 /// </summary> public string Title { get; set; } /// <summary> /// 作者 /// </summary> public string Author { get; set; } /// <summary> /// 链接 /// </summary> public string Url { get; set; } /// <summary> /// HTML /// </summary> public string Html { get; set; } /// <summary> /// Markdown /// </summary> public string Markdown { get; set; } /// <summary> /// 创建时间 /// </summary> public string CreationTime { get; set; } /// <summary> /// 分类 /// </summary> public CategoryDto Category { get; set; } /// <summary> /// 标签列表 /// </summary> public IEnumerable<TagDto> Tags { get; set; } /// <summary> /// 上一篇 /// </summary> public PostForPagedDto Previous { get; set; } /// <summary> /// 下一篇 /// </summary> public PostForPagedDto Next { get; set; } } }同时添加CategoryDto、TagDto、PostForPagedDto。
//CategoryDto.cs namespace Meowv.Blog.Application.Contracts.Blog { public class CategoryDto { /// <summary> /// 分类名称 /// </summary> public string CategoryName { get; set; } /// <summary> /// 展示名称 /// </summary> public string DisplayName { get; set; } } } //TagDto.cs namespace Meowv.Blog.Application.Contracts.Blog { public class TagDto { /// <summary> /// 标签名称 /// </summary> public string TagName { get; set; } /// <summary> /// 展示名称 /// </summary> public string DisplayName { get; set; } } } //PostForPagedDto.cs namespace Meowv.Blog.Application.Contracts.Blog { public class PostForPagedDto { /// <summary> /// 标题 /// </summary> public string Title { get; set; } /// <summary> /// 链接 /// </summary> public string Url { get; set; } } }添加获取文章详情接口和缓存的接口。
//IBlogService.Post.cs public partial interface IBlogService { /// <summary> /// 根据URL获取文章详情 /// </summary> /// <param></param> /// <returns></returns> Task<ServiceResult<PostDetailDto>> GetPostDetailAsync(string url); } //IBlogCacheService.Post.cs public partial interface IBlogCacheService { /// <summary> /// 根据URL获取文章详情 /// </summary> /// <param></param> /// <returns></returns> Task<ServiceResult<PostDetailDto>> GetPostDetailAsync(string url, Func<Task<ServiceResult<PostDetailDto>>> factory); }分别实现这两个接口。
//BlogCacheService.Post.cs public partial class BlogCacheService { private const string KEY_GetPostDetail = "Blog:Post:GetPostDetail-{0}"; /// <summary> /// 根据URL获取文章详情 /// </summary> /// <param></param> /// <param></param> /// <returns></returns> public async Task<ServiceResult<PostDetailDto>> GetPostDetailAsync(string url, Func<Task<ServiceResult<PostDetailDto>>> factory) { return await Cache.GetOrAddAsync(KEY_GetPostDetail.FormatWith(url), factory, CacheStrategy.ONE_DAY); } } //BlogService.Post.cs /// <summary> /// 根据URL获取文章详情 /// </summary> /// <param></param> /// <returns></returns> public async Task<ServiceResult<PostDetailDto>> GetPostDetailAsync(string url) { return await _blogCacheService.GetPostDetailAsync(url, async () => { var result = new ServiceResult<PostDetailDto>(); var post = await _postRepository.FindAsync(x => x.Url.Equals(url)); if (null == post) { result.IsFailed(ResponseText.WHAT_NOT_EXIST.FormatWith("URL", url)); return result; } var category = await _categoryRepository.GetAsync(post.CategoryId); var tags = from post_tags in await _postTagRepository.GetListAsync() join tag in await _tagRepository.GetListAsync() on post_tags.TagId equals tag.Id where post_tags.PostId.Equals(post.Id) select new TagDto { TagName = tag.TagName, DisplayName = tag.DisplayName }; var previous = _postRepository.Where(x => x.CreationTime > post.CreationTime).Take(1).FirstOrDefault(); var next = _postRepository.Where(x => x.CreationTime < post.CreationTime).OrderByDescending(x => x.CreationTime).Take(1).FirstOrDefault(); var postDetail = new PostDetailDto { Title = post.Title, Author = post.Author, Url = post.Url, Html = post.Html, Markdown = post.Markdown, CreationTime = post.CreationTime.TryToDateTime(), Category = new CategoryDto { CategoryName = category.CategoryName, DisplayName = category.DisplayName }, Tags = tags, Previous = previous == null ? null : new PostForPagedDto { Title = previous.Title, Url = previous.Url }, Next = next == null ? null : new PostForPagedDto { Title = next.Title, Url = next.Url } }; result.IsSuccess(postDetail); return result; }); }ResponseText.WHAT_NOT_EXIST是定义在MeowvBlogConsts.cs的常量。
TryToDateTime()和列表查询中的扩展方法一样,转换时间为想要的格式。
简单说一下查询逻辑,先根据参数url,查询是否存在数据,如果文章不存在则返回错误消息。
然后根据 post.CategoryId 就可以查询到当前文章的分类名称。
联合查询post_tags和tag两张表,指定查询条件post.Id,查询当前文章的所有标签。
最后上下篇的逻辑也很简单,上一篇取大于当前文章发布时间的第一篇,下一篇取时间倒序排序并且小于当前文章发布时间的第一篇文章。
最后将所有查询到的数据赋值给输出对象,返回,结束。