學習ASP.NET Core(03)-數據層邏輯層與模型轉換


上一篇我們使用Code First的方式完成了數據庫的建立 ,本章我們來完善一下數據訪問層和業務邏輯層部分的內容


一、IDAL與DAL

根據依賴倒置原則,細節應該依賴於抽象,我們我們要針對抽象,即面向接口進行編程,其好處是解耦和利於重構

1、IDAL實現

1.1、基類接口

這里添加一個CURD操作的基類接口,名為IBaseRepository,其余每個model都對應一個接口並繼承該基類接口。在這之前IDAL層需要添加對Model層的引用。如下:

using System;
using System.Linq;
using System.Threading.Tasks;
using BlogSystem.Model;

namespace BlogSystem.IDAL
{
    /// <summary>
    /// 基類接口
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    public interface IBaseRepository<TEntity> where TEntity : BaseEntity
    {
        /// <summary>
        /// 新增數據
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="saved"></param>
        /// <returns></returns>
        Task CreateAsync(TEntity entity, bool saved = true);

        /// <summary>
        /// 根據Id刪除數據
        /// </summary>
        /// <param name="id"></param>
        /// <param name="saved"></param>
        /// <returns></returns>
        Task RemoveAsync(Guid id, bool saved = true);

        /// <summary>
        /// 根據model刪除對數據
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="saved"></param>
        /// <returns></returns>
        Task RemoveAsync(TEntity entity, bool saved = true);

        /// <summary>
        /// 修改數據
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="saved"></param>
        /// <returns></returns>
        Task EditAsync(TEntity entity, bool saved = true);

        /// <summary>
        /// 通過Id查詢數據
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        Task<TEntity> GetOneByIdAsync(Guid id);

        /// <summary>
        /// 獲取所有數據
        /// </summary>
        /// <returns></returns>
        IQueryable<TEntity> GetAll();

        /// <summary>
        /// 獲取所有數據並排序
        /// </summary>
        /// <returns></returns>
        IQueryable<TEntity> GetAllByOrder(bool asc = true);

        /// <summary>
        /// 統一保存方法
        /// </summary>
        /// <returns></returns>
        Task SavedAsync();

        /// <summary>
        /// 判斷對象是否存在
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        Task<bool> Exists(Guid id);
    }
}

1.2、其余接口

其余的每個model也都定義一個接口並繼承IBaseRepository,給出一個示例,其余需要一一對應如下:

using BlogSystem.Model;

namespace BlogSystem.IDAL
{
    public interface IArticleRepository : IBaseRepository<Article>
    {
    }
}


2、DAL實現

2.1、基類方法

首先DAL層需要添加對Model層和DAL層的引用,然后我們在DAL項目下添加一個名為BaseRepository的類,並繼承基類接口IBaseRepository,添加泛型約束泛型參數為BlogSystem.Model中的BaseEntity,實現如下:

using System;
using System.Linq;
using System.Threading.Tasks;
using BlogSystem.IDAL;
using BlogSystem.Model;
using Microsoft.EntityFrameworkCore;

namespace BlogSystem.DAL
{
    /// <summary>
    /// 實現基類接口
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    public class BaseRepository<TEntity> : IBaseRepository<TEntity> where TEntity : BaseEntity, new()
    {
        private readonly BlogSystemContext _context;

        public BaseRepository(BlogSystemContext context)
        {
            _context = context;
        }

        /// <summary>
        /// 新增數據
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="saved"></param>
        /// <returns></returns>
        public async Task CreateAsync(TEntity entity, bool saved = true)
        {
            _context.Set<TEntity>().Add(entity);
            if (saved) await _context.SaveChangesAsync();
        }

        /// <summary>
        /// 根據Id刪除數據
        /// </summary>
        /// <param name="id"></param>
        /// <param name="saved"></param>
        /// <returns></returns>
        public async Task RemoveAsync(Guid id, bool saved = true)
        {
            var t = new TEntity() { Id = id };
            _context.Entry(t).State = EntityState.Unchanged;
            t.IsRemoved = true;
            if (saved) await _context.SaveChangesAsync();
        }

        /// <summary>
        /// 根據model刪除數據
        /// </summary>
        /// <param name="model"></param>
        /// <param name="saved"></param>
        /// <returns></returns>
        public async Task RemoveAsync(TEntity model, bool saved = true)
        {
            await RemoveAsync(model.Id, saved);
        }

        /// <summary>
        ///  修改數據
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="saved"></param>
        /// <returns></returns>
        public async Task EditAsync(TEntity entity, bool saved = true)
        {
            _context.Entry(entity).State = EntityState.Modified;

            //如果數據沒有發生變化
            if (!_context.ChangeTracker.HasChanges()) return;

            if (saved) await _context.SaveChangesAsync();
        }

        /// <summary>
        /// 通過Id查詢數據
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<TEntity> GetOneByIdAsync(Guid id)
        {
            return await GetAll().FirstOrDefaultAsync(m => m.Id == id);
        }

        /// <summary>
        /// 獲取所有數據
        /// </summary>
        /// <returns></returns>
        public IQueryable<TEntity> GetAll()
        {
            return _context.Set<TEntity>().Where(m => !m.IsRemoved).AsNoTracking();
        }

        /// <summary>
        /// 獲取所有數據並排序
        /// </summary>
        /// <returns></returns>
        public IQueryable<TEntity> GetAllByOrder(bool asc = true)
        {
            var data = GetAll();
            data = asc ? data.OrderBy(m => m.CreateTime) : data.OrderByDescending(m => m.CreateTime);
            return data;
        }

        /// <summary>
        /// 統一保存方法
        /// </summary>
        /// <returns></returns>
        public async Task SavedAsync()
        {
            await _context.SaveChangesAsync();
        }

        /// <summary>
        /// 確認對象是否存在
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<bool> Exists(Guid id)
        {
            return await GetAll().AnyAsync(m => m.Id == id);
        }
    }
}

2.2、其余方法

其余IDAL中的接口采用繼承的方式實現,給出一個示例,其余同理,如下:

    public class ArticleCommentRepository : BaseRepository<ArticleComment>, IArticleCommentRepository
    {
        public ArticleCommentRepository() : base(new BlogSystemContext(new DbContextOptions<BlogSystemContext>()))
        {
        }
    }


二、模型對象

1、概念

在DAL層我們是對數據庫的直接操作,面向的也是我們設計的包含屬性的model;但在BLL層,面向的是業務邏輯,業務邏輯對應的是用戶的操作,在軟件的實際使用過程中,用戶看到的頁面並非對應一個完整的model,頁面可能是model的一部分,也有可能由幾個model的一部分組合而成的。為了解決這類問題,我們通常使用模型對象

2、常用的兩種模型對象

1、Dto(Data Transfer Object):又名數據傳輸對象,常用來定義包含屬性的實體類,它只引用基本數據類型,不引用對象類型,且沒有行為,它只專注於數據本身,一般用於DAL和BLL之間的數據傳輸;

2、ViewModel:又名視圖模型,它根據View創建,是View的數據容器,它專注的是View,用來呈現給用戶,它由一個或多個Dto的組成;

3、實際應用

根據上面的描述,DAL與BLL層的數據交互我們應該使用Dto對象,呈現給頁面時需要使用ViewModel對應,但在實際的開發中,Dto與ViewModel重合度很高,所以部分開發者只使用一種,但兼並兩類角色。此外,Model與Dto/ViewModel之間的轉換,我們可以使用EF的Select方法進行投影解決,或者使用AutoMapper之類的插件。

三、IBLL與ViewModel

這里我們根據功能大類,分為用戶,文章、分類和評論,所以在IBLL中我們暫時先添加這4個接口, 在這之前需要添加對Model層的引用。根據實體對象部分的講述,我們在Model層添加一個ViewModels文件夾,里面用來放置ViewModel對象,ViewModel對象屬性通常會使用一些特性限制用戶的錄入。

1、基類接口

我們發現可以提取出常用的幾個方法,避免重復代碼,操作如下:

using BlogSystem.Model;
using System;
using System.Threading.Tasks;

namespace BlogSystem.IBLL
{
    /// <summary>
    /// 基類服務接口
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    public interface IBaseService<TEntity> where TEntity : BaseEntity
    {
        /// <summary>
        /// 根據Id刪除實體
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        Task RemoveAsync(Guid id);

        /// <summary>
        /// 刪除實體
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        Task RemoveAsync(TEntity entity);

        /// <summary>
        /// 通過Id查詢實體
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        Task<TEntity> GetOneByIdAsync(Guid id);

        /// <summary>
        /// 判斷實體是否存在
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        Task<bool> ExistsAsync(Guid id);
    }
}

2、文章接口與ViewModel

1、在Model層的ViewModel中添加相關的ViewModel,即用戶所視內容需要用到的屬性

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;

namespace BlogSystem.Model.ViewModels
{
    /// <summary>
    /// 創建文章
    /// </summary>
    public class CreateArticleViewModel
    {
        /// <summary>
        /// 創建用戶Id
        /// </summary>
        public Guid UserId { get; set; }

        /// <summary>
        /// 文章標題
        /// </summary>
        [Required]
        public string Title { get; set; }

        /// <summary>
        /// 文章內容
        /// </summary>
        [Required]
        public string Content { get; set; }

        /// <summary>
        /// 文章分類
        /// </summary>
        public List<Guid> CategoryIds { get; set; }
    }
}
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;

namespace BlogSystem.Model.ViewModels
{
    /// <summary>
    /// 編輯文章
    /// </summary>
    public class EditArticleViewModel
    {
        /// <summary>
        /// 文章Id
        /// </summary>
        public Guid Id { get; set; }

        /// <summary>
        /// 文章標題
        /// </summary>
        [Required]
        public string Title { get; set; }

        /// <summary>
        /// 文章內容
        /// </summary>
        [Required]
        public string Content { get; set; }

        /// <summary>
        /// 文章分類
        /// </summary>
        public List<Guid> CategoryIds { get; set; }
    }
}
using System;

namespace BlogSystem.Model.ViewModels
{
    /// <summary>
    /// 文章列表
    /// </summary>
    public class ArticleListViewModel
    {
        /// <summary>
        /// 文章Id
        /// </summary>
        public Guid ArticleId { get; set; }

        /// <summary>
        /// 文章標題
        /// </summary>
        public string Title { get; set; }

        /// <summary>
        /// 文章內容
        /// </summary>
        public string Content { get; set; }

        /// <summary>
        /// 創建時間
        /// </summary>
        public DateTime CreateTime { get; set; }

        /// <summary>
        /// 賬號
        /// </summary>
        public string Account { get; set; }

        /// <summary>
        /// 頭像
        /// </summary>
        public string ProfilePhoto { get; set; }
    }
}
using System;
using System.Collections.Generic;

namespace BlogSystem.Model.ViewModels
{
    /// <summary>
    /// 文章詳情
    /// </summary>
    public class ArticleDetailsViewModel
    {
        /// <summary>
        /// 文章Id
        /// </summary>
        public Guid Id { get; set; }

        /// <summary>
        /// 文章標題
        /// </summary>
        public string Title { get; set; }

        /// <summary>
        /// 文章內容
        /// </summary>
        public string Content { get; set; }

        /// <summary>
        /// 創建時間
        /// </summary>
        public DateTime CreateTime { get; set; }

        /// <summary>
        /// 作者
        /// </summary>
        public string Account { get; set; }

        /// <summary>
        /// 頭像
        /// </summary>
        public string ProfilePhoto { get; set; }

        /// <summary>
        /// 分類Id
        /// </summary>
        public List<Guid> CategoryIds { get; set; }

        /// <summary>
        /// 分類名稱
        /// </summary>
        public List<string> CategoryNames { get; set; }

        /// <summary>
        /// 看好人數
        /// </summary>
        public int GoodCount { get; set; }
        /// <summary>
        /// 不看好人數
        /// </summary>
        public int BadCount { get; set; }

    }
}

2、接口實現:IArticleService繼承基類接口,並添加如下方法:

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using BlogSystem.Model;
using BlogSystem.Model.ViewModels;

namespace BlogSystem.IBLL
{
    /// <summary>
    /// 文章接口
    /// </summary>
    public interface IArticleService : IBaseService<Article>
    {
        /// <summary>
        /// 新增文章
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        Task CreateArticleAsync(CreateArticleViewModel model);

        /// <summary>
        /// 編輯文章
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        Task EditArticleAsync(EditArticleViewModel model);

        /// <summary>
        /// 通過Id獲取文章詳情
        /// </summary>
        /// <param name="articleId"></param>
        /// <returns></returns>
        Task<ArticleDetailsViewModel> GetArticleDetailsByArticleIdAsync(Guid articleId);

        /// <summary>
        /// 通過用戶Id獲取文章列表
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        Task<List<ArticleListViewModel>> GetArticlesByUserIdAsync(Guid userId);

        /// <summary>
        /// 通過分類Id獲取所有文章
        /// </summary>
        /// <param name="categoryId"></param>
        /// <returns></returns>
        Task<List<ArticleListViewModel>> GetArticlesByCategoryIdAsync(Guid categoryId);

        /// <summary>
        /// 通過用戶Id獲取文章數量
        /// </summary>
        /// <param name="userid"></param>
        /// <returns></returns>
        Task<int> GetArticleCountByUserIdAsync(Guid userid);

        /// <summary>
        /// 點贊文章
        /// </summary>
        /// <param name="articleId"></param>
        /// <returns></returns>
        Task AddGoodCount(Guid articleId);

        /// <summary>
        /// 點滅文章
        /// </summary>
        /// <param name="articleId"></param>
        /// <returns></returns>
        Task AddBadCount(Guid articleId);
    }
}

3、分類接口與ViewModel

1、在Model層的ViewMode文件夾中添加相關的ViewModel

using System;
using System.ComponentModel.DataAnnotations;

namespace BlogSystem.Model.ViewModels
{
    public class CreateOrEditCategoryViewModel
    {
        /// <summary>
        /// 分類名稱
        /// </summary>
        [Required]
        public string CategoryName { get; set; }

        /// <summary>
        /// 創建用戶Id
        /// </summary>
        public Guid UserId { get; set; }
    }
}
namespace BlogSystem.Model.ViewModels
{
    public class CategoryListViewModel
    {
        /// <summary>
        /// 分類名稱
        /// </summary>
        public string CategoryName { get; set; }
    }
}

2、分類接口:繼承基類接口,並添加如下方法:

using BlogSystem.Model;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using BlogSystem.Model.ViewModels;

namespace BlogSystem.IBLL
{
    /// <summary>
    /// 分類服務接口
    /// </summary>
    public interface ICategoryService : IBaseService<Category>
    {
        /// <summary>
        /// 創建分類
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        Task CreateCategory(CreateOrEditCategoryViewModel model);

        /// <summary>
        /// 編輯分類
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        Task EditCategory(CreateOrEditCategoryViewModel model);

        /// <summary>
        /// 通過用戶Id獲取所有分類
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        Task<List<CategoryListViewModel>> GetCategoryByUserIdAsync(Guid userId);
    }
}

4、用戶接口與ViewModel

1、在Model層的ViewModel文件夾中添加相關的ViewModel

using System;
using System.ComponentModel.DataAnnotations;

namespace BlogSystem.Model.ViewModels
{
    /// <summary>
    /// 用戶注冊
    /// </summary>
    public class RegisterViewModel
    {
        /// <summary>
        /// 賬號
        /// </summary>
        [Required]
        public string Account { get; set; }

        /// <summary>
        /// 密碼
        /// </summary>
        [Required]
        public string Password { get; set; }

        /// <summary>
        /// 確認密碼
        /// </summary>
        [Required]
        public string RequirePassword { get; set; }
    }
}
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;

namespace BlogSystem.Model.ViewModels
{
    /// <summary>
    /// 用戶登錄
    /// </summary>
    public class LoginViewModel
    {
        /// <summary>
        /// 賬號
        /// </summary>
        [Required]
        public string Account { get; set; }

        /// <summary>
        /// 密碼
        /// </summary>
        [Required]
        public string Password { get; set; }
    }
}

using System;
using System.ComponentModel.DataAnnotations;

namespace BlogSystem.Model.ViewModels
{
    /// <summary>
    /// 修改用戶密碼
    /// </summary>
    public class ChangePwdViewModel
    {
        /// <summary>
        /// 用戶Id
        /// </summary>
        public Guid UserId { get; set; }

        /// <summary>
        /// 舊密碼
        /// </summary>
        [Required]
        public string OldPassword { get; set; }

        /// <summary>
        /// 新密碼
        /// </summary>
        [Required]
        public string NewPassword { get; set; }

        /// <summary>
        /// 確認新密碼
        /// </summary>
        [Required]
        public string RequirePassword { get; set; }
    }
}
using System;
using System.ComponentModel.DataAnnotations;

namespace BlogSystem.Model.ViewModels
{
    /// <summary>
    /// 修改用戶頭像
    /// </summary>
    public class ChangeUserPhotoViewModel
    {
        /// <summary>
        /// 用戶Id
        /// </summary>
        public Guid UserId { get; set; }

        /// <summary>
        /// 用戶頭像
        /// </summary>
        [Required]
        public string ProfilePhoto { get; set; }
    }
}
using System;

namespace BlogSystem.Model.ViewModels
{
    /// <summary>
    /// 修改用戶資料
    /// </summary>
    public class ChangeUserInfoViewModel
    {
        /// <summary>
        /// 用戶Id
        /// </summary>
        public Guid UserId { get; set; }

        /// <summary>
        /// 賬號
        /// </summary>
        public string Account { get; set; }

        /// <summary>
        /// 出生日期
        /// </summary>
        public DateTime BirthOfDate { get; set; }

        /// <summary>
        /// 性別
        /// </summary>
        public Gender Gender { get; set; }
    }
}
using System;

namespace BlogSystem.Model.ViewModels
{
    /// <summary>
    /// 用戶詳細信息-點擊查看主頁
    /// </summary>
    public class UserDetailsViewModel
    {
        /// <summary>
        /// 用戶Id
        /// </summary>
        public Guid UserId { get; set; }
        /// <summary>
        /// 賬號
        /// </summary>
        public string Account { get; set; }
        /// <summary>
        /// 頭像
        /// </summary>
        public string ProfilePhoto { get; set; }
        /// <summary>
        /// 年齡
        /// </summary>
        public int Age { get; set; }
        /// <summary>
        /// 性別
        /// </summary>
        public Gender Gender { get; set; }
        /// <summary>
        /// 用戶等級
        /// </summary>
        public Level Level { get; set; }
        /// <summary>
        /// 粉絲數
        /// </summary>
        public int FansNum { get; set; }
        /// <summary>
        /// 關注數
        /// </summary>
        public int FocusNum { get; set; }
    }
}

2、用戶接口:添加用戶方法,如下:

using System;
using BlogSystem.Model;
using BlogSystem.Model.ViewModels;
using System.Threading.Tasks;

namespace BlogSystem.IBLL
{
    /// <summary>
    /// 用戶服務接口
    /// </summary>
    public interface IUserService : IBaseService<User>
    {
        /// <summary>
        /// 注冊
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        Task Register(RegisterViewModel model);

        /// <summary>
        /// 登錄成功返回userId
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        Task<Guid> Login(LoginViewModel model);

        /// <summary>
        /// 修改用戶密碼
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        Task ChangePassword(ChangePwdViewModel model);

        /// <summary>
        /// 修改用戶頭像
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        Task ChangeUserPhoto(ChangeUserPhotoViewModel model);

        /// <summary>
        /// 修改用戶信息
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        Task ChangeUserInfo(ChangeUserInfoViewModel model);

        /// <summary>
        /// 使用account獲取用戶信息
        /// </summary>
        /// <param name="account"></param>
        /// <returns></returns>
        Task<UserDetailsViewModel> GetUserInfoByAccount(string account);
    }
}

5、評論接口與ViewModel

1、在Model層的ViewModel文件夾中添加相關的ViewModel

using System;

namespace BlogSystem.Model.ViewModels
{
    public class CommentListViewModel
    {
        /// <summary>
        /// 文章Id
        /// </summary>
        public Guid ArticleId { get; set; }

        /// <summary>
        /// 用戶Id
        /// </summary>
        public Guid UserId { get; set; }

        /// <summary>
        /// 賬號
        /// </summary>
        public string Account { get; set; }

        /// <summary>
        /// 評論Id
        /// </summary>
        public Guid CommentId { get; set; }

        /// <summary>
        /// 評論內容
        /// </summary>
        public string CommentContent { get; set; }

        /// <summary>
        /// 創建時間
        /// </summary>
        public DateTime CreateTime { get; set; }

    }
}

2、評論接口:添加接口方法,如下:

using BlogSystem.Model;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using BlogSystem.Model.ViewModels;

namespace BlogSystem.IBLL
{
    /// <summary>
    /// 評論服務接口
    /// </summary>
    public interface ICommentService : IBaseService<ArticleComment>
    {
        /// <summary>
        /// 添加評論
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        Task CreateComment(ArticleComment model);

        /// <summary>
        /// 添加回復型評論
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        Task CreateReplyComment(CommentReply model);

        /// <summary>
        /// 通過文章Id獲取所有評論
        /// </summary>
        /// <param name="articleId"></param>
        /// <returns></returns>
        Task<List<CommentListViewModel>> GetCommentsByArticleIdAsync(Guid articleId);
    }
}

我們這里暫時只是添加了目前考慮到的一些功能,后續以上的功能可能會進行相關的調整。

四、BLL實現

首先,我們需要對BLL層添加對Model,IDAL,IBLL的引用

1、基類方法

實現基類方法,如下:

using System;
using System.Threading.Tasks;
using BlogSystem.IBLL;
using BlogSystem.IDAL;
using BlogSystem.Model;

namespace BlogSystem.BLL
{
    /// <summary>
    /// 基類方法
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    public class BaseService<TEntity> : IBaseService<TEntity> where TEntity : BaseEntity, new()
    {
        //通過在子類的構造函數中注入,這里是基類,不用構造函數
        public IBaseRepository<TEntity> BaseRepository;

        /// <summary>
        /// 根據Id刪除對象
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task RemoveAsync(Guid id)
        {
            await BaseRepository.RemoveAsync(id);
        }

        /// <summary>
        /// 根據實體刪除對象
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public async Task RemoveAsync(TEntity entity)
        {
            await BaseRepository.RemoveAsync(entity);
        }

        /// <summary>
        /// 查詢對象
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<TEntity> GetOneByIdAsync(Guid id)
        {
            return await BaseRepository.GetOneByIdAsync(id);
        }

        /// <summary>
        /// 判斷對象是否存在
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<bool> ExistsAsync(Guid id)
        {
            return await BaseRepository.Exists(id);
        }
    }
}

2、文章方法

文章方法實現如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using BlogSystem.IBLL;
using BlogSystem.IDAL;
using BlogSystem.Model;
using BlogSystem.Model.ViewModels;
using Microsoft.EntityFrameworkCore;

namespace BlogSystem.BLL
{
    /// <summary>
    /// 實現文章接口方法
    /// </summary>
    public class ArticleService : BaseService<Article>, IArticleService
    {
        private readonly IArticleRepository _articleRepository;
        private readonly IArticleInCategoryRepository _articleInCategoryRepository;
        private readonly ICategoryRepository _categoryRepository;

        //構造函數注入相關接口
        public ArticleService(IArticleRepository articleRepository, IArticleInCategoryRepository articleInCategoryRepository,
        ICategoryRepository categoryRepository)
        {
            _articleRepository = articleRepository;
            BaseRepository = articleRepository;
            _articleInCategoryRepository = articleInCategoryRepository;
            _categoryRepository = categoryRepository;
        }

        /// <summary>
        /// 創建文章
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public async Task CreateArticleAsync(CreateArticleViewModel model)
        {
            //新增文章
            var article = new Article()
            {
                UserId = model.UserId,
                Title = model.Title,
                Content = model.Content
            };
            await _articleRepository.CreateAsync(article);

            //新增文章所屬分類
            var articleId = article.Id;
            foreach (var categoryId in model.CategoryIds)
            {
                await _articleInCategoryRepository.CreateAsync(new ArticleInCategory()
                {
                    ArticleId = articleId,
                    CategoryId = categoryId
                }, false);
            }
            await _articleInCategoryRepository.SavedAsync();
        }

        /// <summary>
        /// 編輯文章
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public async Task EditArticleAsync(EditArticleViewModel model)
        {
            //保存文章更新
            var article = await _articleRepository.GetOneByIdAsync(model.Id);
            article.Title = model.Title;
            article.Content = model.Content;
            await _articleRepository.EditAsync(article);

            //刪除所屬分類
            var categoryIds = _articleInCategoryRepository.GetAll();
            foreach (var categoryId in categoryIds)
            {
                await _articleInCategoryRepository.RemoveAsync(categoryId, false);
            }
            //添加所屬分類
            foreach (var categoryId in model.CategoryIds)
            {
                await _articleInCategoryRepository.CreateAsync(new ArticleInCategory()
                {
                    ArticleId = model.Id,
                    CategoryId = categoryId
                }, false);
            }
            //統一保存
            await _articleInCategoryRepository.SavedAsync();
        }

        /// <summary>
        /// 獲取文章詳情
        /// </summary>
        /// <param name="articleId"></param>
        /// <returns></returns>
        public async Task<ArticleDetailsViewModel> GetArticleDetailsByArticleIdAsync(Guid articleId)
        {
            var data = await _articleRepository.GetAll().Include(m => m.User).Where(m => m.Id == articleId)
                .Select(m => new ArticleDetailsViewModel
                {
                    Id = m.Id,
                    Title = m.Title,
                    Content = m.Content,
                    CreateTime = m.CreateTime,
                    Account = m.User.Account,
                    ProfilePhoto = m.User.ProfilePhoto,
                    GoodCount = m.GoodCount,
                    BadCount = m.BadCount
                }).FirstAsync();
            //處理分類
            var categories = await _articleInCategoryRepository.GetAll().Include(m => m.Category)
                .Where(m => m.ArticleId == data.Id).ToListAsync();
            data.CategoryIds = categories.Select(m => m.CategoryId).ToList();
            data.CategoryNames = categories.Select(m => m.Category.CategoryName).ToList();
            return data;
        }

        /// <summary>
        /// 根據用戶Id獲取文章列表信息
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        public async Task<List<ArticleListViewModel>> GetArticlesByUserIdAsync(Guid userId)
        {
            var list = await _articleRepository.GetAllByOrder(false).Include(m => m.User).Where(m => m.UserId == userId)
                .Select(m => new ArticleListViewModel()
                {
                    ArticleId = m.Id,
                    Title = m.Title,
                    Content = m.Content,
                    CreateTime = m.CreateTime,
                    Account = m.User.Account,
                    ProfilePhoto = m.User.ProfilePhoto
                }).ToListAsync();
            return list;
        }

        /// <summary>
        /// 通過分類Id獲取文章列表
        /// </summary>
        /// <param name="categoryId"></param>
        /// <returns></returns>
        public async Task<List<ArticleListViewModel>> GetArticlesByCategoryIdAsync(Guid categoryId)
        {
            var data = await _categoryRepository.GetOneByIdAsync(categoryId);
            var userId = data.UserId;
            return await GetArticlesByUserIdAsync(userId);
        }

        /// <summary>
        /// 獲取用戶文章數量
        /// </summary>
        /// <param name="userid"></param>
        /// <returns></returns>
        public async Task<int> GetArticleCountByUserIdAsync(Guid userid)
        {
            return await _articleRepository.GetAll().CountAsync(m => m.UserId == userid);
        }

        /// <summary>
        /// 看好數量+1
        /// </summary>
        /// <param name="articleId"></param>
        /// <returns></returns>
        public async Task AddGoodCount(Guid articleId)
        {
            var article = await _articleRepository.GetOneByIdAsync(articleId);
            article.GoodCount++;
            await _articleRepository.EditAsync(article);
        }

        /// <summary>
        /// 不看好數量+1
        /// </summary>
        /// <param name="articleId"></param>
        /// <returns></returns>
        public async Task AddBadCount(Guid articleId)
        {
            var article = await _articleRepository.GetOneByIdAsync(articleId);
            article.BadCount--;
            await _articleRepository.EditAsync(article);
        }
    }
}

3、分類方法

實現分類方法,如下:

using BlogSystem.IBLL;
using BlogSystem.IDAL;
using BlogSystem.Model;
using BlogSystem.Model.ViewModels;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace BlogSystem.BLL
{
    public class CategoryService : BaseService<Category>, ICategoryService
    {
        private readonly ICategoryRepository _categoryRepository;

        public CategoryService(ICategoryRepository categoryRepository)
        {
            _categoryRepository = categoryRepository;
            BaseRepository = categoryRepository;
        }

        /// <summary>
        /// 創建分類
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public async Task CreateCategory(CreateOrEditCategoryViewModel model)
        {
            await _categoryRepository.CreateAsync(new Category()
            {
                UserId = model.UserId,
                CategoryName = model.CategoryName
            });
        }

        /// <summary>
        /// 編輯分類
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public async Task EditCategory(CreateOrEditCategoryViewModel model)
        {
            await _categoryRepository.EditAsync(new Category()
            {
                UserId = model.UserId,
                CategoryName = model.CategoryName
            });
        }

        /// <summary>
        ///  通過用戶Id獲取所有分類
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        public Task<List<CategoryListViewModel>> GetCategoryByUserIdAsync(Guid userId)
        {
            return _categoryRepository.GetAll().Where(m => m.UserId == userId).Select(m => new CategoryListViewModel
            {
                CategoryName = m.CategoryName
            }).ToListAsync();
        }
    }
}

4、用戶方法

實現用戶方法,如下:

using BlogSystem.IBLL;
using BlogSystem.IDAL;
using BlogSystem.Model;
using BlogSystem.Model.ViewModels;
using Microsoft.EntityFrameworkCore;
using System;
using System.Linq;
using System.Threading.Tasks;

namespace BlogSystem.BLL
{
    public class UserService : BaseService<User>, IUserService
    {
        private readonly IUserRepository _userRepository;

        public UserService(IUserRepository userRepository)
        {
            _userRepository = userRepository;
            BaseRepository = userRepository;
        }

        /// <summary>
        /// 用戶注冊
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public async Task Register(RegisterViewModel model)
        {
           //判斷賬戶是否存在
            if (!await _userRepository.GetAll().AnyAsync(m => m.Account == model.Account))
            {
                await _userRepository.CreateAsync(new User()
                {
                    Account = model.Account,
                    Password = model.Password
                });
            }
        }

        /// <summary>
        /// 用戶登錄
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public async Task<Guid> Login(LoginViewModel model)
        {
            var user = await _userRepository.GetAll().FirstOrDefaultAsync(m => m.Account == model.Account && m.Password == model.Password);
            return user != null ? user.Id : new Guid();
        }

        /// <summary>
        /// 修改用戶密碼
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public async Task ChangePassword(ChangePwdViewModel model)
        {
            if (await _userRepository.GetAll().AnyAsync(m => m.Id == model.UserId && m.Password == model.OldPassword))
            {
                var user = await _userRepository.GetAll().FirstOrDefaultAsync(m => m.Id == model.UserId && m.Password == model.OldPassword);
                user.Password = model.NewPassword;
                await _userRepository.EditAsync(user);
            }
        }

        /// <summary>
        /// 修改用戶照片
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public async Task ChangeUserPhoto(ChangeUserPhotoViewModel model)
        {
            var user = await _userRepository.GetAll().FirstAsync(m => m.Id == model.UserId);
            user.ProfilePhoto = model.ProfilePhoto;
            await _userRepository.EditAsync(user);
        }

        /// <summary>
        /// 修改用戶信息
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public async Task ChangeUserInfo(ChangeUserInfoViewModel model)
        {
            var user = await _userRepository.GetAll().FirstAsync(m => m.Id == model.UserId);
            user.Account = model.Account;
            user.Gender = model.Gender;
            user.BirthOfDate = model.BirthOfDate;
            await _userRepository.EditAsync(user);
        }

        /// <summary>
        /// 通過賬號名稱獲取用戶信息
        /// </summary>
        /// <param name="account"></param>
        /// <returns></returns>
        public async Task<UserDetailsViewModel> GetUserInfoByAccount(string account)
        {
            if (await _userRepository.GetAll().AnyAsync(m => m.Account == account))
            {
                return await _userRepository.GetAll().Where(m => m.Account == account).Select(m =>
                    new UserDetailsViewModel()
                    {
                        UserId = m.Id,
                        Account = m.Account,
                        ProfilePhoto = m.ProfilePhoto,
                        Age = DateTime.Now.Year - m.BirthOfDate.Year,
                        Gender = m.Gender,
                        Level = m.Level,
                        FansNum = m.FansNum,
                        FocusNum = m.FocusNum
                    }).FirstAsync();
            }
            return new UserDetailsViewModel();
        }
    }
}

5、評論方法

實現評論方法,如下:

using BlogSystem.IBLL;
using BlogSystem.IDAL;
using BlogSystem.Model;
using BlogSystem.Model.ViewModels;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace BlogSystem.BLL
{
    public class CommentService : BaseService<ArticleComment>, ICommentService
    {
        private readonly IArticleCommentRepository _commentRepository;
        private readonly ICommentReplyRepository _commentReplyRepository;

        public CommentService(IArticleCommentRepository commentRepository, ICommentReplyRepository commentReplyRepository)
        {
            _commentRepository = commentRepository;
            BaseRepository = commentRepository;
            _commentReplyRepository = commentReplyRepository;
        }

        /// <summary>
        /// 添加評論
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public async Task CreateComment(ArticleComment model)
        {
            await _commentRepository.CreateAsync(model);
        }

        /// <summary>
        /// 添加回復型評論
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public async Task CreateReplyComment(CommentReply model)
        {
            await _commentReplyRepository.CreateAsync(model);
        }

        /// <summary>
        /// 根據文章Id獲取評論信息
        /// </summary>
        /// <param name="articleId"></param>
        /// <returns></returns>
        public async Task<List<CommentListViewModel>> GetCommentsByArticleIdAsync(Guid articleId)
        {
            return await _commentReplyRepository.GetAllByOrder(false).Where(m => m.ArticleId == articleId)
                .Include(m => m.ArticleComment).Include(m => m.User).Select(m => new CommentListViewModel()
                {
                    ArticleId = m.ArticleId,
                    UserId = m.UserId,
                    Account = m.User.Account,
                    CommentId = m.Id,
                    CommentContent = m.Content,
                    CreateTime = m.CreateTime
                })
                .ToListAsync();
        }
    }
}

本章只是從整體上將DAL層和BLL的進行了初步的完善,后續會進一步調整,完~

本人知識點有限,若文中有錯誤的地方請及時指正,方便大家更好的學習和交流。

本文的代碼結構和方法參考了B站一位UP主的視頻內容,地址如下:任生風影

原創文章聲明


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM