zoukankan      html  css  js  c++  java
  • 学习ASP.NET Core(02)-分层与EF迁移

    上一篇简单介绍了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,成功更新数据表至数据库

    本章完~

    本人知识点有限,若文中有错误的地方请及时指正,方便大家更好的学习和交流

    原创文章声明
  • 相关阅读:
    openCV使用
    Object-C知识点 (二) 控件的实用属性
    Linux 配置JDK + MyEclipse
    虚拟机+linux+大杂烩
    THREE.js代码备份——webgl
    THREE.js代码备份——webgl
    THREE.js代码备份——canvas_ascii_effect(以AscII码显示图形)
    THREE.js代码备份——canvas
    THREE.js代码备份——canvas_lines(随机点、画线)
    THREE.js代码备份——线框cube、按键、鼠标控制
  • 原文地址:https://www.cnblogs.com/Jscroop/p/12833618.html
Copyright © 2011-2022 走看看