上一篇簡單介紹了ASP.NET Core Web項目的結構,本章我們來對項目進行簡單的分層和使用Code First的方式建立數據庫
一、分層
1、項目說明
之前是想做一個Mvc項目,但是主要還是想學習一下前后端分離方面的內容,並且寫博客的目的也是為了學習和記錄一些新的東西,所以就改成ASP.NET Core WebApi項目了;
該系列的目標是建立一個博客項目,功能上目前打算實現用戶管理、文章管理和評論管理三部分的內容,后續再看情況是否進行功能上的擴展
2、分層規划
項目邏輯相對簡單,這里我們采用簡單的三層架構模式,為了解耦為DAL和BLL添加了對應的接口層,另外添加了模型層Model,工具層Common,所以在原先的基礎上添加6個.NET Core類庫項目,項目結構如下圖:
二、建立模型層
1、Model的基類
將model共有的幾個欄位提取出來作為基類。分別是Id、創建時間和是否被刪除,如下:
/// <summary>
/// Model的基類
/// </summary>
public class BaseEntity
{
/// <summary>
/// 唯一標識Id
/// </summary>
public Guid Id { get; set; } = Guid.NewGuid();
/// <summary>
/// 創建時間
/// </summary>
public DateTime CreateTime { get; set; } = DateTime.Now;
/// <summary>
/// 是否被刪除(偽刪除)
/// </summary>
public bool IsRemoved { get; set; }
}
2、用戶類
性別是新建的一個枚舉類,另外后期可能會寫權限方面的東西,所以還有一個用戶等級枚舉類,默認為普通用戶。用戶類要繼承自剛剛新建的基類,並設定一些特性進行限制,比如限定為必填項等等,當然這邊只是對存入數據的一個限定,實際上我們還需要對用戶錄入頁面進行限定,那將是Dto和ViewModel需要處理的事件,這里先不展開
/// <summary>
/// 性別枚舉
/// </summary>
public enum Gender
{
男=0,
女=1,
保密=2
}
/// <summary>
/// 用戶等級枚舉
/// </summary>
public enum Level
{
普通用戶 = 0,
會員用戶 = 1,
系統管理員=2
}
using System;
using System.ComponentModel.DataAnnotations;
namespace BlogSystem.Model
{
/// <summary>
/// 用戶
/// </summary>
public class User : BaseEntity
{
/// <summary>
/// 賬戶
/// </summary>
[Required, StringLength(40)]
public string Account { get; set; }
/// <summary>
/// 密碼
/// </summary>
[Required, StringLength(200)]
public string Password { get; set; }
/// <summary>
/// 頭像
/// </summary>
public string ProfilePhoto { get; set; }
/// <summary>
/// 出生日期
/// </summary>
public DateTime BirthOfDate { get; set; }
/// <summary>
/// 性別
/// </summary>
public Gender Gender { get; set; }
/// <summary>
/// 用戶等級
/// </summary>
public Level Level { get; set; } = Level.普通用戶;
/// <summary>
/// 粉絲數
/// </summary>
public int FansNum { get; set; }
/// <summary>
/// 關注數
/// </summary>
public int FocusNum { get; set; }
}
}
3、用戶關注
用戶Id和關注用戶Id同樣是來源於用戶表,這里外鍵的處理方法是引入了兩個不同名稱的User,但是這樣處理會存在級聯刪除的問題,但由於我們采用的是偽刪除的方式,並沒有真正的刪除,所以我們會在后面的DbContext方法中關閉級聯刪除以解決此問題
using System;
using System.ComponentModel.DataAnnotations.Schema;
namespace BlogSystem.Model
{
/// <summary>
/// 用戶關注表
/// </summary>
public class UserFocus : BaseEntity
{
/// <summary>
/// 用戶編號
/// </summary>
[ForeignKey(nameof(User))]
public Guid UserId { get; set; }
public User User { get; set; }
/// <summary>
/// 關注用戶編號
/// </summary>
[ForeignKey(nameof(Focus))]
public Guid FocusId { get; set; }
public User Focus { get; set; }
}
}
4、文章類
每篇文章都存在一個發表人,所以我們在這里添加了外鍵,如下:
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace BlogSystem.Model
{
/// <summary>
/// 文章
/// </summary>
public class Article : BaseEntity
{
/// <summary>
/// 文章標題
/// </summary>
[Required]
public string Title { get; set; }
/// <summary>
/// 文章內容
/// </summary>
[Required, Column(TypeName = "text")]
public string Content { get; set; }
/// <summary>
/// 發表人的Id,用戶表的外鍵
/// </summary>
[ForeignKey(nameof(User))]
public Guid UserId { get; set; }
public User User { get; set; }
/// <summary>
/// 看好人數
/// </summary>
public int GoodCount { get; set; }
/// <summary>
/// 不看好人數
/// </summary>
public int BadCount { get; set; }
/// <summary>
/// 文章查看所需等級
/// </summary>
public Level Level { get; set; } = Level.普通用戶;
}
}
5、分類信息
分類信息需要對應到用戶,所以同樣存在一個外鍵對應,建立如下:
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace BlogSystem.Model
{
/// <summary>
/// 分類
/// </summary>
public class Category : BaseEntity
{
/// <summary>
/// 分類名稱
/// </summary>
[Required]
public string CategoryName { get; set; }
/// <summary>
/// 分類對應的用戶
/// </summary>
[ForeignKey(nameof(User))]
public Guid UserId { get; set; }
public User User { get; set; }
}
}
6、文章對應的分類
每篇文章對應一個或多個分類,同樣存在外鍵對應關系,建立如下:
using System;
using System.ComponentModel.DataAnnotations.Schema;
namespace BlogSystem.Model
{
/// <summary>
/// 文章所屬分類
/// </summary>
public class ArticleInCategory : BaseEntity
{
/// <summary>
/// 分類Id
/// </summary>
[ForeignKey(nameof(Category))]
public Guid CategoryId { get; set; }
public Category Category { get; set; }
/// <summary>
/// 文章Id
/// </summary>
[ForeignKey(nameof(Article))]
public Guid ArticleId { get; set; }
public Article Article { get; set; }
}
}
7、評論功能
評論存在1個帖子對應M個評論,M個評論對應N個回復的情況,所以拆分成文章評論表和評論回復表,如下:
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace BlogSystem.Model
{
/// <summary>
/// 文章評論表
/// </summary>
public class ArticleComment : BaseEntity
{
/// <summary>
/// 評論的文章ID
/// </summary>
[ForeignKey(nameof(Article))]
public Guid ArticleId { get; set; }
public Article Article { get; set; }
/// <summary>
/// 評論用戶ID
/// </summary>
[ForeignKey(nameof(User))]
public Guid UserId { get; set; }
public User User { get; set; }
/// <summary>
/// 評論內容
/// </summary>
[Required, StringLength(800)]
public string Content { get; set; }
}
}
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace BlogSystem.Model
{
/// <summary>
/// 評論回復表
/// </summary>
public class CommentReply : BaseEntity
{
/// <summary>
/// 回復指向的評論Id
/// </summary>
[ForeignKey(nameof(ArticleComment))]
public Guid CommentId { get; set; }
public ArticleComment ArticleComment { get; set; }
/// <summary>
/// 回復指向的用戶Id
/// </summary>
[ForeignKey(nameof(ToUser))]
public Guid ToUserId { get; set; }
public User ToUser { get; set; }
/// <summary>
/// 文章ID
/// </summary>
[ForeignKey(nameof(Article))]
public Guid ArticleId { get; set; }
public Article Article { get; set; }
/// <summary>
/// 用戶Id
/// </summary>
[ForeignKey(nameof(User))]
public Guid UserId { get; set; }
public User User { get; set; }
/// <summary>
/// 回復的內容
/// </summary>
[Required, StringLength(800)]
public string Content { get; set; }
}
}
三、EF遷移
1、數據庫選擇
VS內置了一個"小型"的SQL Server數據庫,這里我們就使用它作為我們的數據庫。右擊依賴項,選擇Nuget包,我們需要安裝Microsoft.EntityFrameworkCore.SqlServer和Microsoft.EntityFrameworkCore,但因為依賴關系安裝Microsoft.EntityFrameworkCore.SqlServer時會一並裝上Microsoft.EntityFrameworkCore,如下:
2、添加DbContext
1、DbContext是實體類與數據庫之間的橋梁,負責與數據庫進行交互。我們添加一個名為BlogSystemContext的類,繼承自DbContext
2、建表時有提到級聯刪除的問題,EF是默認開啟級聯刪除的,即存在外鍵的情況下,刪除一筆數據,關聯數據也會被刪除,上面有說明會存在沖突,所以這里我們重寫方OnModelCreateing法將其關閉。並在OnConfiguring方法中配置數據庫連接,如下:
using Microsoft.EntityFrameworkCore;
using System.Linq;
namespace BlogSystem.Model
{
public class BlogSystemContext : DbContext
{
public BlogSystemContext()
{
}
public BlogSystemContext(DbContextOptions<BlogSystemContext> options) : base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
//關閉級聯刪除
var foreignKeys = modelBuilder.Model.GetEntityTypes().SelectMany(m => m.GetForeignKeys()).Where(x => x.DeleteBehavior == DeleteBehavior.Cascade);
foreach (var foreign in foreignKeys)
{
foreign.DeleteBehavior = DeleteBehavior.Restrict;
}
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
//配置數據庫連接
optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=BlogSystem;Trusted_Connection=True;");
}
public DbSet<Article> Articles { get; set; }
public DbSet<ArticleComment> ArticleComments { get; set; }
public DbSet<ArticleInCategory> ArticleInCategories { get; set; }
public DbSet<Category> Categories { get; set; }
public DbSet<CommentReply> CommentReplies { get; set; }
public DbSet<User> Users { get; set; }
public DbSet<UserFocus> UserFocuses { get; set; }
}
}
3、使用Migration進行遷移
1、遷移使用Nuget安裝Microsoft.EntityFrameworkCore.Tools和Microsoft.EntityFrameworkCore.Design,由於依賴關系只需要安裝Microsoft.EntityFrameworkCore.Tools即可,安裝后選擇程序包管理控制台,如下:
2、遷移前首先要確認默認項目對應的是BlogSystem.Model輸入添加遷移指令add-migration InitialTable,成功后會出現Migrations文件夾,里面包含數據庫初始化文件和快照文件;執行update-database,成功更新數據表至數據庫
本章完~
本人知識點有限,若文中有錯誤的地方請及時指正,方便大家更好的學習和交流